├── LIL.creator ├── LIL.includes ├── LIL.config ├── hello.lil ├── .gitignore ├── fileio.lil ├── LIL.files ├── return.lil ├── result.lil ├── dll ├── lildll.wpj ├── lildll.c └── lil.tgt ├── filter.lil ├── jaileval.lil ├── Makefile.bcc ├── local.lil ├── lil.wpj ├── vim ├── readme.txt └── lil.vim ├── trim.lil ├── dollar.lil ├── downeval.lil ├── lists.lil ├── and.lil ├── call.lil ├── topeval.lil ├── enveval.lil ├── Makefile ├── strings.lil ├── robot.lil ├── liblil.tgt ├── renamefunc.lil ├── lil.tgt ├── funcs.lil ├── upeval.lil ├── oop_animals.lil ├── mandelbrot.lil ├── oop.lil ├── .project ├── sm.lil ├── catcher.lil ├── lil.h ├── main.c ├── .cproject └── readme.txt /LIL.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /LIL.includes: -------------------------------------------------------------------------------- 1 | lilcgi 2 | lili -------------------------------------------------------------------------------- /LIL.config: -------------------------------------------------------------------------------- 1 | // ADD PREDEFINED MACROS HERE! 2 | -------------------------------------------------------------------------------- /hello.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Hello world in lil 3 | # 4 | 5 | print "Hello, world!" 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lil 2 | build/ 3 | *.dll 4 | *.lib 5 | *.lk1 6 | *.o 7 | *.a 8 | *.so 9 | *.dylib 10 | *.map 11 | *.mk1 12 | *.obj 13 | *.sym 14 | *.mk 15 | *.lb1 16 | *.exe 17 | 18 | *.tds -------------------------------------------------------------------------------- /fileio.lil: -------------------------------------------------------------------------------- 1 | # 2 | # As asked in http://stackoverflow.com/questions/3538156 3 | # 4 | 5 | store fileio.txt "hello\n" 6 | store fileio.txt "[read fileio.txt]world\n" 7 | print [index [split [read fileio.txt] "\n"] 1] 8 | -------------------------------------------------------------------------------- /LIL.files: -------------------------------------------------------------------------------- 1 | lil.c 2 | lil.h 3 | lilcgi/db.c 4 | lilcgi/db.h 5 | lilcgi/lilcgi.c 6 | lilcgi/md5.c 7 | lilcgi/md5.h 8 | lilcgi/sqlite3.c 9 | lilcgi/sqlite3.h 10 | lilcgi/sqlite3ext.h 11 | lili/lili.c 12 | lili/lili.h 13 | lili/lili_macosx.m 14 | lili/main.c 15 | main.c -------------------------------------------------------------------------------- /return.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Shows how return can be omitted 3 | # 4 | 5 | func uses_return {x} { 6 | set y [expr $x * $x] 7 | return $y 8 | } 9 | 10 | func does_not_use_return {x} { 11 | expr $x * $x 12 | } 13 | 14 | foreach {uses_return does_not_use_return} {print "The result of '$i 10' is [$i 10]"} 15 | 16 | # Code from GitHub issue #2 17 | func test args {expr 100} 18 | print [test] 19 | 20 | -------------------------------------------------------------------------------- /result.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Showing how 'result' can be used to define the return value of a 3 | # function without actually breaking out of the function. 4 | # 5 | 6 | func bits-for {x} { 7 | result 1 8 | while {$x > 1} { 9 | set x [expr $x >> 1] 10 | result [expr [result] + 1] 11 | } 12 | } 13 | 14 | foreach {0 1 2 10 30 63 64 100 300} {print "Bits for ${i}:\t[bits-for $i]} 15 | 16 | -------------------------------------------------------------------------------- /dll/lildll.wpj: -------------------------------------------------------------------------------- 1 | 40 2 | projectIdent 3 | 0 4 | VpeMain 5 | 1 6 | WRect 7 | 3136 8 | 2048 9 | 5744 10 | 6485 11 | 2 12 | MProject 13 | 3 14 | MCommand 15 | 0 16 | 4 17 | MCommand 18 | 0 19 | 1 20 | 5 21 | WFileName 22 | 7 23 | lil.tgt 24 | 6 25 | WVList 26 | 1 27 | 7 28 | VComponent 29 | 8 30 | WRect 31 | 197 32 | 180 33 | 2618 34 | 3773 35 | 0 36 | 0 37 | 9 38 | WFileName 39 | 7 40 | lil.tgt 41 | 0 42 | 4 43 | 7 44 | -------------------------------------------------------------------------------- /filter.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Test for the "filter" function. The "filter" function can be used to 3 | # filter a list using an expression which is evaluated for each item in 4 | # the list. 5 | # 6 | 7 | # print all known functions with name lengths less than 5 characters 8 | set known-funcs [reflect funcs] 9 | set predicate {[length $x] < 5} 10 | set small-named-funcs [filter $known-funcs $predicate] 11 | print "Functions with small names:" 12 | foreach $small-named-funcs {print " $i"} 13 | 14 | -------------------------------------------------------------------------------- /jaileval.lil: -------------------------------------------------------------------------------- 1 | # 2 | # jaileval test 3 | # 4 | 5 | func my_part {} { 6 | return "where are you?" 7 | } 8 | 9 | # this code will be executed in its own LIL runtime 10 | set code { 11 | func my_part {} { 12 | set global msg "here i am" 13 | set global foo "hey dude, $msg" 14 | } 15 | 16 | my_part 17 | 18 | return $foo 19 | } 20 | 21 | set bar [jaileval $code] 22 | set msg [my_part] 23 | 24 | print $msg 25 | print $bar 26 | -------------------------------------------------------------------------------- /Makefile.bcc: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for Borland C/C++ Compiler 5.5 3 | # 4 | 5 | BCC = bcc32 6 | TLIB = tlib 7 | 8 | lil.exe: liblil.lib main.obj 9 | $(BCC) -e$@ main.obj liblil.lib 10 | 11 | liblil.lib: lil.obj 12 | $(TLIB) liblil.lib +lil.obj 13 | 14 | lil.obj: lil.c 15 | $(BCC) -DLILINT_INT64 -D_MSC_VER -w-8057 -w-8060 -c -olil.obj lil.c 16 | 17 | main.obj: main.c 18 | $(BCC) -DLILINT_INT64 -DWIN32 -w-8057 -c -omain.obj main.c 19 | 20 | .PHONY: clean 21 | clean: 22 | del lil.obj 23 | del main.obj 24 | del liblil.lib 25 | del lil.exe 26 | 27 | -------------------------------------------------------------------------------- /local.lil: -------------------------------------------------------------------------------- 1 | # 2 | # local can be used to "localize" variables in an environment, which is useful 3 | # to make sure that a global variable with the same name as a local one will 4 | # not be modified. 5 | # 6 | 7 | func bits-for {x} { 8 | local y bits 9 | set y 0 bits 0 10 | while {$y <= $x} { 11 | inc bits 12 | set y [expr 1 << $bits] 13 | } 14 | return $bits 15 | } 16 | 17 | set y 1001 18 | set bits [bits-for $y] 19 | set x 45 20 | set bitsx [bits-for $x] 21 | print "$bits bits needed for $y" 22 | print "$bitsx bits needed for $x" 23 | 24 | -------------------------------------------------------------------------------- /lil.wpj: -------------------------------------------------------------------------------- 1 | 40 2 | projectIdent 3 | 0 4 | VpeMain 5 | 1 6 | WRect 7 | 2106 8 | 3280 9 | 4016 10 | 4759 11 | 2 12 | MProject 13 | 3 14 | MCommand 15 | 0 16 | 4 17 | MCommand 18 | 0 19 | 2 20 | 5 21 | WFileName 22 | 7 23 | lil.tgt 24 | 6 25 | WFileName 26 | 10 27 | liblil.tgt 28 | 7 29 | WVList 30 | 2 31 | 8 32 | VComponent 33 | 9 34 | WRect 35 | 64 36 | 113 37 | 2352 38 | 2446 39 | 0 40 | 0 41 | 10 42 | WFileName 43 | 7 44 | lil.tgt 45 | 0 46 | 1 47 | 11 48 | VComponent 49 | 12 50 | WRect 51 | 1168 52 | 1024 53 | 2608 54 | 2190 55 | 0 56 | 0 57 | 13 58 | WFileName 59 | 10 60 | liblil.tgt 61 | 0 62 | 0 63 | 8 64 | -------------------------------------------------------------------------------- /vim/readme.txt: -------------------------------------------------------------------------------- 1 | vimfile for lil 2 | =============== 3 | 4 | This directory contains a vimfile for lil syntax highlighting. It is 5 | required both for plain lil files (*.lil) and for extended lil files for 6 | other projects (such as lilart's *.lilart and *.ladoc). 7 | 8 | To install this file in your vim installation put it in your syntax syntax 9 | directory under ~/.vim (or wherever the vim configuration directory is). 10 | See :help new-filetype for instructions on how to make vim automatically set 11 | the filetype for *.ladoc and *.lilart files to ladoc and lilart. Personally 12 | i use the "C" method described in the new-filetype help section. 13 | 14 | 15 | -------------------------------------------------------------------------------- /trim.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Test for trim, ltrim and rtrim. These functions can be used to remove 3 | # characters from the beginning and end of a string (ltrim and rtrim remove 4 | # only the beginning or ending characters). 5 | # 6 | 7 | set str " Hello, world! " 8 | 9 | print "The string is '$str'" 10 | print "After trim: '[trim $str]'" 11 | print "After ltrim: '[ltrim $str]'" 12 | print "After rtrim: '[rtrim $str]'" 13 | 14 | print "Let's remove spaces, commas and exclamation marks for all words:" 15 | 16 | print " [foreach [split $str] {quote [trim $i {,!}]}]" 17 | 18 | print "Alternative method using \"split\" and \"filter\":" 19 | 20 | print " [filter [split $str {,! }] {[length $x] > 0}" 21 | 22 | -------------------------------------------------------------------------------- /dollar.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Test for "reflect dollar-prefix" 3 | # 4 | 5 | # Set some variable 6 | set foo bar 7 | 8 | # Use dollar expansion with the default prefix ('set ') 9 | print $foo 10 | 11 | # Define a custom set-like function which prints the variable in question 12 | func my-set {name} { 13 | print "Requested the value of [set name]" 14 | return [set name] 15 | } 16 | 17 | # Try it 18 | print [my-set foo] 19 | 20 | # Now use reflect dollar-prefix to report and change the prefix 21 | print "Current dollar-prefix: '[reflect dollar-prefix]'" 22 | reflect dollar-prefix {my-set } 23 | print "New dollar prefix: '[reflect dollar-prefix]'" 24 | 25 | # Try using the new dollar prefix 26 | print $foo 27 | 28 | -------------------------------------------------------------------------------- /downeval.lil: -------------------------------------------------------------------------------- 1 | # 2 | # downeval is the complement of upeval: it allows code inside an upeval block 3 | # to be executed back in the level of the most recent upeval. This can be 4 | # used to access data from an upper environment and work on it at the upeval's 5 | # environment. Obviously downeval makes sense only if it used from inside an 6 | # upeval (otherwise it acts like plain old eval). 7 | # 8 | 9 | func print-the-list {} { 10 | set items {} 11 | upeval { 12 | foreach $some-list { 13 | downeval " 14 | print Adding item $i 15 | append items $i 16 | " 17 | } 18 | } 19 | print Items: $items 20 | } 21 | 22 | func do-stuff {} { 23 | set some-list [list foo bar baz blah moo boo] 24 | print-the-list 25 | } 26 | 27 | do-stuff 28 | 29 | -------------------------------------------------------------------------------- /lists.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Lists test 3 | # 4 | 5 | # dumps the list 6 | func dumplist {t l} { 7 | print "${t}: $l" 8 | set i 1 9 | foreach it $l { 10 | print " item ${i}: $it" 11 | inc i 12 | } 13 | print "[count $l] items" 14 | } 15 | 16 | set l [list foo bar baz bad] 17 | dumplist "Initial list" $l 18 | 19 | print "Item at index 2: [index $l 2]" 20 | 21 | print "Appending Chlorine..." 22 | append l Chlorine 23 | dumplist "List after Chlorine" $l 24 | 25 | print "Appending Hello, world!..." 26 | append l "Hello, world!" 27 | dumplist "List after Hello, world!" $l 28 | 29 | print "Substituting the list" 30 | set l [subst $l] 31 | dumplist "List after substitution" $l 32 | 33 | print "Map list to variables" 34 | lmap $l foox barx bamia 35 | foreach "foox barx bamia" {print "$i is '$${i}'"} 36 | -------------------------------------------------------------------------------- /and.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Short-circuit logical "and" macro-like function using upeval and downeval. 3 | # The "and" function will evaluate each one of its arguments at the upper 4 | # environment in a call to downeval which sets the argument's result to the 5 | # "v" variable. As soon as the "v" is not a true value, the evaluation stops 6 | # and any possible side-effects the evaluation of the arguments might have, do 7 | # not happen. 8 | # 9 | 10 | func and args { 11 | foreach [slice $args 1] { 12 | upeval "downeval \"set v \"\[${i}\]" 13 | if not $v { return 0 } 14 | } 15 | return 1 16 | } 17 | 18 | # print and return 19 | func priret {a} { 20 | print "Got '$a'" 21 | return $a 22 | } 23 | 24 | set a 0 25 | set final [and {priret [set a 3]} {priret 0} {priret [set a 32]}] 26 | 27 | print "Final is $final" 28 | print "a is $a" 29 | -------------------------------------------------------------------------------- /call.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Calling code 3 | # 4 | 5 | # using eval 6 | print "* Evaluating 'print Hello, world!'" 7 | eval {print "Hello, world!"} 8 | 9 | # sourcing external file 10 | print "* Sourcing hello.lil" 11 | source hello.lil 12 | 13 | # an alternative way to source external files (which however might behave 14 | # differently if the host program wishes to forbit reading but allow sourcing) 15 | print "* Evaluating the string returned by 'read hello.lil'" 16 | eval [read hello.lil] 17 | 18 | # calling functions indirectly 19 | func foo {arg} { 20 | print "This is function foo and the arg is $arg" 21 | } 22 | 23 | func bar {arg} { 24 | print "This is function bar and the arg... who cares" 25 | } 26 | 27 | func callfunc {name arg} { 28 | print "* Let's call the function '${name}' with the argument '${arg}'" 29 | $name $arg 30 | } 31 | 32 | foreach f "foo bar print" { 33 | foreach a {{tralala} {3 + 3}} {callfunc $f $a} 34 | } 35 | -------------------------------------------------------------------------------- /topeval.lil: -------------------------------------------------------------------------------- 1 | # 2 | # topeval is like an "extreme" version of upeval: it evaluates code at the 3 | # topmost (global/root) environment. Like with upeval, downeval can be used 4 | # to evaluate code in the environment from where topeval was called. 5 | # 6 | 7 | func does-something {} { 8 | topeval { 9 | # this will show the global x, not the one from calls-something 10 | print "x inside topeval before modifying it is $x" 11 | set x 42 12 | downeval { 13 | set y [expr $x * 10] 14 | } 15 | } 16 | print "y in does-something is $y" 17 | } 18 | 19 | func calls-something {} { 20 | local x 21 | set x 33 22 | does-something # this will modify the global x, not the local one! 23 | print "x in calls-something is $x and y is $y" 24 | } 25 | 26 | set x 10 27 | set y 20 28 | print "x in global is $x and y is $y" 29 | calls-something 30 | print "now x in global is $x and y is $y" 31 | 32 | -------------------------------------------------------------------------------- /enveval.lil: -------------------------------------------------------------------------------- 1 | # 2 | # enveval is a code evaluation function like eval, topeval, upeval, jaileval, 3 | # etc that can be used to evaluate code inside its own environment. The code 4 | # has no access to the enveval's calling environment and is executed almost 5 | # like a function's body. 6 | # 7 | 8 | func do-something {} { 9 | local x 10 | set x 32 11 | set y 10 12 | set z 88 13 | # here both y and z variables will be copied to the new environment, but 14 | # only y will be copied back to the current environment 15 | enveval {y z} {y} { 16 | local x 17 | print "x inside enveval before changing is ${x}, y is $y and z is $z" 18 | set x 100 y 44 z 123 19 | print "x inside enveval after changing is ${x}, y is $y and z is $z" 20 | quote 32 21 | } 22 | print "x inside do-something is ${x}, y is $y and z is $z" 23 | } 24 | 25 | print "setting x in the global environment to 300" 26 | set x 300 27 | do-something 28 | print "x in the global environment is $x" 29 | 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for lil. It requires GNU Make. 3 | # 4 | 5 | PREFIX = /usr/local 6 | LIL_PROGRAM = lil 7 | LIL_LIBRARY = liblil.a 8 | BININSTALL = $(PREFIX)/bin 9 | MANINSTALL = $(PREFIX)/man/man1 10 | CFLAGS ?= -g3 -std=c99 -pedantic -Wall -Wextra -Wno-long-long -Wno-unused-parameter 11 | LDFLAGS ?= -g -L. 12 | 13 | LIL_SOURCES = lil.c 14 | LIL_PROGRAM_SOURCES = main.c 15 | 16 | LIL_OBJECTS = $(patsubst %.c,%.o,$(LIL_SOURCES)) 17 | LIL_PROGRAM_OBJECTS = $(patsubst %.c,%.o,$(LIL_PROGRAM_SOURCES)) 18 | 19 | HEADERS = $(wildcard *.h) 20 | 21 | .PHONY: all 22 | all: $(LIL_LIBRARY) $(LIL_PROGRAM) 23 | 24 | $(LIL_LIBRARY): $(LIL_OBJECTS) 25 | $(AR) rcs $(LIL_LIBRARY) $(LIL_OBJECTS) 26 | 27 | $(LIL_PROGRAM): $(LIL_PROGRAM_OBJECTS) $(LIL_LIBRARY) 28 | $(CC) $(LDFLAGS) -o $(LIL_PROGRAM) $(LIL_PROGRAM_OBJECTS) -llil -lm 29 | 30 | $(LIL_PROGRAM_OBJECTS) $(LIL_OBJECTS): %.o: %.c $(HEADERS) 31 | $(CC) -c $(CFLAGS) $< -o $@ 32 | 33 | .PHONY: clean 34 | clean: 35 | $(RM) -f $(LIL_PROGRAM_OBJECTS) $(LIL_OBJECTS) 36 | $(RM) -f $(LIL_LIBRARY) $(LIL_PROGRAM) $(LILCGI_PROGRAM) 37 | -------------------------------------------------------------------------------- /dll/lildll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LIL DLL - Little Interpreted Language DLL 3 | * Copyright (C) 2010 Kostas Michalopoulos 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any damages 7 | * arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any purpose, 10 | * including commercial applications, and to alter it and redistribute it 11 | * freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you must not 14 | * claim that you wrote the original software. If you use this software 15 | * in a product, an acknowledgment in the product documentation would be 16 | * appreciated but is not required. 17 | * 2. Altered source versions must be plainly marked as such, and must not be 18 | * misrepresented as being the original software. 19 | * 3. This notice may not be removed or altered from any source distribution. 20 | * 21 | * Kostas Michalopoulos 22 | */ 23 | 24 | #include 25 | 26 | BOOL APIENTRY LibMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved) 27 | { 28 | return 1; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /strings.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Strings test 3 | # 4 | 5 | set a "This is a string" 6 | set b "This is another string" 7 | 8 | print "String a: ${a}\nString b: $b" 9 | 10 | print "String a length: [length $a]" 11 | print "String b length: [length $b]" 12 | 13 | print "Character at length/2 in a: [charat $a [expr [length $a] / 2]]" 14 | print "Character at length/2 in b: [charat $b [expr [length $b] / 2]]" 15 | 16 | print "Character code at length/2 in a: [codeat $a [expr [length $a] / 2]]" 17 | print "Character code at length/2 in b: [codeat $b [expr [length $b] / 2]]" 18 | 19 | print "Middle of a: '[substr $a [expr [length $a] / 3] [expr ( [length $a] / 3 ) * 2]]'" 20 | print "Middle of b: '[substr $b [expr [length $b] / 3] [expr ( [length $b] / 3 ) * 2]]'" 21 | 22 | print "Index of 'string' in a: [strpos $a string]" 23 | print "Index of 'string' in b: [strpos $b string]" 24 | 25 | print "String comparison between a and b yields [strcmp $a $b]" 26 | print "String equality between a and b yeilds [streq $a $b]" 27 | 28 | print "String a with 'string' replaced to 'foo': [repstr $a string foo]" 29 | print "String b with 'string' replaced to 'foo': [repstr $b string foo]" 30 | 31 | print "String a splitted:" 32 | foreach [split $a] {print " part: '${i}'"} 33 | print "String b splitted:" 34 | foreach [split $b] {print " part: '${i}'"} 35 | -------------------------------------------------------------------------------- /robot.lil: -------------------------------------------------------------------------------- 1 | # 2 | # A test for sm.lil 3 | # 4 | # The following article explains the ideas behind this code: 5 | # http://badsector.posterous.com/a-flexible-and-simple-script-driven-state-mac 6 | # 7 | 8 | source sm.lil 9 | 10 | # define robot-update- functions 11 | sm:func robot-update {} { 12 | idle { print $obj is idling } 13 | seek { print $obj is seeking } 14 | flee { print $obj is fleeing } 15 | attack { print $obj is attacking } 16 | die { print $obj is dying } 17 | default { print $obj is doing nothing } 18 | } 19 | 20 | # define state check functions 21 | func robot-flee-check {sm} { return 0 } 22 | 23 | # define state enter functions 24 | func robot-attack-enter {sm} { 25 | print "play sound attack for [sm:obj $sm]" 26 | } 27 | 28 | func robot-die-enter {sm} { 29 | print "destroy [sm:obj $sm]" 30 | } 31 | 32 | # define state exit functions 33 | func robot-attack-exit {sm} { 34 | print "kill sound attack for [sm:obj $sm]" 35 | } 36 | 37 | # a dummy object 38 | set robot [sm:new robot "fred" idle] 39 | 40 | func update {} { robot-update $robot } 41 | func transit {to} { sm:transit $robot $to } 42 | 43 | update 44 | transit seek 45 | update 46 | transit flee 47 | update 48 | transit idle 49 | update 50 | transit attack 51 | update 52 | transit cast 53 | update 54 | transit die 55 | update 56 | 57 | -------------------------------------------------------------------------------- /liblil.tgt: -------------------------------------------------------------------------------- 1 | 40 2 | targetIdent 3 | 0 4 | MProject 5 | 1 6 | MComponent 7 | 0 8 | 2 9 | WString 10 | 3 11 | LIB 12 | 3 13 | WString 14 | 5 15 | n_2sn 16 | 1 17 | 0 18 | 1 19 | 4 20 | MCommand 21 | 0 22 | 5 23 | MCommand 24 | 0 25 | 6 26 | MItem 27 | 10 28 | liblil.lib 29 | 7 30 | WString 31 | 3 32 | LIB 33 | 8 34 | WVList 35 | 0 36 | 9 37 | WVList 38 | 0 39 | -1 40 | 1 41 | 1 42 | 0 43 | 10 44 | WPickList 45 | 4 46 | 11 47 | MItem 48 | 3 49 | *.c 50 | 12 51 | WString 52 | 4 53 | COBJ 54 | 13 55 | WVList 56 | 1 57 | 14 58 | MCState 59 | 15 60 | WString 61 | 3 62 | WCC 63 | 16 64 | WString 65 | 26 66 | ?????Force ANSI compliance 67 | 1 68 | 1 69 | 17 70 | WVList 71 | 0 72 | -1 73 | 1 74 | 1 75 | 0 76 | 18 77 | MItem 78 | 5 79 | lil.c 80 | 19 81 | WString 82 | 4 83 | COBJ 84 | 20 85 | WVList 86 | 0 87 | 21 88 | WVList 89 | 0 90 | 11 91 | 1 92 | 1 93 | 0 94 | 22 95 | MItem 96 | 3 97 | *.h 98 | 23 99 | WString 100 | 3 101 | NIL 102 | 24 103 | WVList 104 | 0 105 | 25 106 | WVList 107 | 0 108 | -1 109 | 1 110 | 1 111 | 0 112 | 26 113 | MItem 114 | 5 115 | lil.h 116 | 27 117 | WString 118 | 3 119 | NIL 120 | 28 121 | WVList 122 | 0 123 | 29 124 | WVList 125 | 0 126 | 22 127 | 1 128 | 1 129 | 0 130 | -------------------------------------------------------------------------------- /renamefunc.lil: -------------------------------------------------------------------------------- 1 | # 2 | # LIL test for "rename" and "unusedname". This test shows how to implement an 3 | # alternative "func" which will store information about a function in 4 | # addition to declaring a new function. 5 | # 6 | # Note that this code is for illustrative purposes on how rename can be used. 7 | # In practice it might be a better idea to use a custom name (like doc-func) 8 | # for this purpose. 9 | # 10 | 11 | # Generate a random name, store it and rename func to that 12 | set real-func [unusedname] 13 | rename func $real-func 14 | 15 | # Declare a new "func" which uses the previous one and also stores info about 16 | # the function in a global variable 17 | $real-func func {name info args code} { 18 | set global "--doc-func-${name}-info" $info 19 | append global "--doc-func-names" $name 20 | $real-func $name $args $code 21 | } 22 | 23 | # Let's declare a couple of functions 24 | func add "Adds two numbers and returns the result" {a b} { 25 | return [expr (${a}) + (${b})] 26 | } 27 | 28 | func pew "Prints pew pew" {} { 29 | print "pew pew" 30 | } 31 | 32 | # ...and use them 33 | 34 | pew 35 | print [add 3 4] 36 | 37 | # Now let's show some info about the known documented functions 38 | print "Known functions:" 39 | foreach $--doc-func-names { 40 | print " Name: $i" 41 | print " Arguments: [reflect args $i]" 42 | print " Information: $'--doc-func-${i}-info'" 43 | } 44 | 45 | -------------------------------------------------------------------------------- /lil.tgt: -------------------------------------------------------------------------------- 1 | 40 2 | targetIdent 3 | 0 4 | MProject 5 | 1 6 | MComponent 7 | 0 8 | 2 9 | WString 10 | 4 11 | NEXE 12 | 3 13 | WString 14 | 5 15 | nc2en 16 | 1 17 | 0 18 | 1 19 | 4 20 | MCommand 21 | 0 22 | 5 23 | MCommand 24 | 0 25 | 6 26 | MItem 27 | 7 28 | lil.exe 29 | 7 30 | WString 31 | 4 32 | NEXE 33 | 8 34 | WVList 35 | 0 36 | 9 37 | WVList 38 | 0 39 | -1 40 | 1 41 | 1 42 | 0 43 | 10 44 | WPickList 45 | 4 46 | 11 47 | MItem 48 | 3 49 | *.c 50 | 12 51 | WString 52 | 4 53 | COBJ 54 | 13 55 | WVList 56 | 1 57 | 14 58 | MVState 59 | 15 60 | WString 61 | 3 62 | WCC 63 | 16 64 | WString 65 | 23 66 | ?????Macro definitions: 67 | 1 68 | 17 69 | WString 70 | 5 71 | WIN32 72 | 0 73 | 18 74 | WVList 75 | 0 76 | -1 77 | 1 78 | 1 79 | 0 80 | 19 81 | MItem 82 | 6 83 | main.c 84 | 20 85 | WString 86 | 4 87 | COBJ 88 | 21 89 | WVList 90 | 0 91 | 22 92 | WVList 93 | 0 94 | 11 95 | 1 96 | 1 97 | 0 98 | 23 99 | MItem 100 | 5 101 | *.lib 102 | 24 103 | WString 104 | 3 105 | NIL 106 | 25 107 | WVList 108 | 0 109 | 26 110 | WVList 111 | 0 112 | -1 113 | 1 114 | 1 115 | 0 116 | 27 117 | MItem 118 | 10 119 | liblil.lib 120 | 28 121 | WString 122 | 3 123 | NIL 124 | 29 125 | WVList 126 | 0 127 | 30 128 | WVList 129 | 0 130 | 23 131 | 1 132 | 1 133 | 0 134 | -------------------------------------------------------------------------------- /funcs.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Functions test 3 | # 4 | 5 | # direct function definition and call 6 | func foo {a b} { 7 | print "This is foo and a is '$a' while b is '$b'" 8 | } 9 | 10 | foo "hello, world" "hello to you too" 11 | 12 | # pseudo-anonymous function definition with the result assigned to 'bar' 13 | set bar [func {a b} { 14 | print "This is bar and a is '$a' while b is '$b'" 15 | }] 16 | 17 | $bar "hi again" "and again" 18 | 19 | # similarly, but without arguments (they are stored as a list in 'args'). This 20 | # behaves the same as a function declared like 'func name args {...}' which 21 | # means that the first item in the list will be the function's name - in this 22 | # case a randomly generated name 23 | set moo [func { 24 | print "I'm moo and i've got these arguments:" 25 | set c 0 26 | foreach $args { 27 | print " argument $c is '${i}'" 28 | inc c 29 | } 30 | }] 31 | 32 | $moo this is a good day 33 | 34 | # applying a function to a list - the function returns some value to be printed 35 | func apply-to-list {title list func} { 36 | print ${title}: 37 | foreach $list {print [$func $i]} 38 | set body [reflect body $func] 39 | if $body { 40 | print "The function's code is\n $body" 41 | } 42 | } 43 | 44 | set list [list {bad's day} {good's day} {eh??}] 45 | apply-to-list "Splitting the list items" $list split 46 | apply-to-list "Getting list items' length" $list length 47 | apply-to-list "Using an anonymous function with the list" $list [func {a} {return "The length of $a is [length $a]"}] 48 | -------------------------------------------------------------------------------- /dll/lil.tgt: -------------------------------------------------------------------------------- 1 | 40 2 | targetIdent 3 | 0 4 | MProject 5 | 1 6 | MComponent 7 | 0 8 | 2 9 | WString 10 | 4 11 | NDLL 12 | 3 13 | WString 14 | 5 15 | n_2dn 16 | 1 17 | 0 18 | 1 19 | 4 20 | MCommand 21 | 0 22 | 5 23 | MCommand 24 | 0 25 | 6 26 | MItem 27 | 7 28 | lil.dll 29 | 7 30 | WString 31 | 4 32 | NDLL 33 | 8 34 | WVList 35 | 0 36 | 9 37 | WVList 38 | 1 39 | 10 40 | ActionStates 41 | 11 42 | WString 43 | 5 44 | &Make 45 | 12 46 | WVList 47 | 0 48 | -1 49 | 1 50 | 1 51 | 0 52 | 13 53 | WPickList 54 | 5 55 | 14 56 | MItem 57 | 3 58 | *.c 59 | 15 60 | WString 61 | 4 62 | COBJ 63 | 16 64 | WVList 65 | 1 66 | 17 67 | MVState 68 | 18 69 | WString 70 | 3 71 | WCC 72 | 19 73 | WString 74 | 23 75 | ?????Macro definitions: 76 | 1 77 | 20 78 | WString 79 | 6 80 | LILDLL 81 | 0 82 | 21 83 | WVList 84 | 0 85 | -1 86 | 1 87 | 1 88 | 0 89 | 22 90 | MItem 91 | 8 92 | ..\lil.c 93 | 23 94 | WString 95 | 4 96 | COBJ 97 | 24 98 | WVList 99 | 0 100 | 25 101 | WVList 102 | 0 103 | 14 104 | 1 105 | 1 106 | 0 107 | 26 108 | MItem 109 | 8 110 | lildll.c 111 | 27 112 | WString 113 | 4 114 | COBJ 115 | 28 116 | WVList 117 | 0 118 | 29 119 | WVList 120 | 0 121 | 14 122 | 1 123 | 1 124 | 0 125 | 30 126 | MItem 127 | 3 128 | *.h 129 | 31 130 | WString 131 | 3 132 | NIL 133 | 32 134 | WVList 135 | 0 136 | 33 137 | WVList 138 | 0 139 | -1 140 | 1 141 | 1 142 | 0 143 | 34 144 | MItem 145 | 8 146 | ..\lil.h 147 | 35 148 | WString 149 | 3 150 | NIL 151 | 36 152 | WVList 153 | 0 154 | 37 155 | WVList 156 | 0 157 | 30 158 | 1 159 | 1 160 | 0 161 | -------------------------------------------------------------------------------- /upeval.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Test for "upeval". The "upeval" function allows code to be evaluated in the 3 | # upper (parent) environment of the current one. This makes possible for code 4 | # defined in a function to access the variables of the caller of the function 5 | # and - if the caller is another function - make it return, effectively 6 | # providing the functionality that other languages provide via the use of 7 | # macros but with being part of the program's execution instead of 8 | # preprocessing. 9 | # 10 | 11 | # This function will execute the code "if {$i > somenumber} return" in the 12 | # caller's environment, causing it to return if a variable named "i" is 13 | # greater than the given number 14 | func check {num} { 15 | upeval "if {\$i > $num} return" 16 | } 17 | 18 | # This function will try to print numbers from 0 to 99, although it will 19 | # fail to do so because "check 10" will cause it to return once "i" goes 20 | # above 10. 21 | func do-stuff {} { 22 | for {set i 0} {$i < 100} {inc i} { 23 | check 10 24 | print $i 25 | } 26 | } 27 | 28 | do-stuff 29 | 30 | # This function returns some imaginary people info based on some id 31 | # Returns 0 if the person was not found, otherwise it sets the vars 32 | # specified by the first-name-var and last-name-var to the first and last 33 | # name of the person 34 | func get-person-info {id first-name-var last-name-var} { 35 | set first-names [list Karina Dona Erik Cody Hugh] 36 | set last-names [list Addario Mcneece Wootten Tokarz Severns] 37 | if {$id < 0 || $id >= [count $first-names]} {return 0} 38 | upeval "set $first-name-var [index $first-names $id]" 39 | upeval "set $last-name-var [index $last-names $id]" 40 | return 1 41 | } 42 | 43 | if [get-person-info 3 first-name last-name] { 44 | print "First name: $first-name" 45 | print "Last name: $last-name" 46 | } { 47 | print "Unknown user" 48 | } 49 | 50 | -------------------------------------------------------------------------------- /oop_animals.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Simple object oriented example: animals. This script declares four prototype 3 | # objects: animal, cat, dog and fish. The animal object is used as a base for 4 | # the other three objects. 5 | # 6 | 7 | # Declares all the functions needed for prototype-based OOP 8 | source oop.lil 9 | 10 | ################## 11 | # Animal prototype 12 | 13 | # The init message is sent after the object has been created with "new". This 14 | # method expects the animal's name as the first and only argument 15 | method Animal init {name} { 16 | objset name $name 17 | } 18 | 19 | # The talk message returns something that resembles speech for an animal 20 | method Animal talk {} { 21 | return "(the animal cannot talk)" 22 | } 23 | 24 | # The get-name message returns the animal's name 25 | method Animal get-name {} { 26 | return [objset name] 27 | } 28 | 29 | ################################################# 30 | # Cat prototype. Cat extends the Animal prototype 31 | 32 | extend Animal Cat 33 | 34 | method Cat talk {} { 35 | return "meow" 36 | } 37 | 38 | ################################################# 39 | # Dog prototype. Dog extends the Animal prototype 40 | 41 | extend Animal Dog 42 | 43 | method Dog talk {} { 44 | return "woof" 45 | } 46 | 47 | ############################################################################# 48 | # Fish prototype. Fish extends the Animal prototype, but doesn't add anything 49 | 50 | extend Animal Fish 51 | 52 | ###################### 53 | # Ok, let's use these! 54 | 55 | set animals [list \ 56 | [new Cat Alice] \ 57 | [new Cat Oswald] \ 58 | [new Dog Max] \ 59 | [new Fish Atlas]] 60 | 61 | foreach animal $animals { 62 | print "[$animal get-name] ([typeof $animal]):\t[$animal talk]" 63 | } 64 | 65 | # 66 | # Expected output: 67 | # ---------------- 68 | # 69 | # Alice (Cat): meow 70 | # Oswald (Cat): meow 71 | # Max (Dog): woof 72 | # Atlas (Fish): (the animal cannot talk) 73 | # 74 | 75 | -------------------------------------------------------------------------------- /mandelbrot.lil: -------------------------------------------------------------------------------- 1 | # 2 | # A mandelbrot generator that outputs a PBM file. This can be used to measure 3 | # performance differences between LIL versions and measure performance 4 | # bottlenecks (although keep in mind that LIL is not supposed to be a fast 5 | # language, but a small one which depends on C for the slow parts - in a real 6 | # program where for some reason mandelbrots are required, the code below would 7 | # be written in C). The code is based on the mandelbrot test for the Computer 8 | # Language Benchmarks Game at http://shootout.alioth.debian.org/ 9 | # 10 | # In my current computer (Intel Core2Quad Q9550 @ 2.83GHz) running x86 Linux 11 | # the results are (using the default 256x256 size): 12 | # 13 | # 2m3.634s - commit 1c41cdf89f4c1e039c9b3520c5229817bc6274d0 (Jan 10 2011) 14 | # 15 | # To test call 16 | # 17 | # time ./lil mandelbrot.lil > mandelbrot.pbm 18 | # 19 | # with an optimized version of lil (compiled with CFLAGS=-O3 make). 20 | # 21 | 22 | set width [expr $argv] 23 | if not $width { set width 256 } 24 | set height $width 25 | set bit_num 0 26 | set byte_acc 0 27 | set iter 50 28 | set limit 2.0 29 | 30 | write "P4\n${width} ${height}\n" 31 | 32 | for {set y 0} {$y < $height} {inc y} { 33 | for {set x 0} {$x < $width} {inc x} { 34 | set Zr 0.0 Zi 0.0 Tr 0.0 Ti 0.0 35 | set Cr [expr 2.0 * $x / $width - 1.5] 36 | set Ci [expr 2.0 * $y / $height - 1.0] 37 | for {set i 0} {$i < $iter && $Tr + $Ti <= $limit * $limit} {inc i} { 38 | set Zi [expr 2.0 * $Zr * $Zi + $Ci] 39 | set Zr [expr $Tr - $Ti + $Cr] 40 | set Tr [expr $Zr * $Zr] 41 | set Ti [expr $Zi * $Zi] 42 | } 43 | 44 | set byte_acc [expr $byte_acc << 1] 45 | if [expr $Tr + $Ti <= $limit * $limit] { 46 | set byte_acc [expr $byte_acc | 1] 47 | } 48 | 49 | inc bit_num 50 | 51 | if [expr $bit_num == 8] { 52 | writechar $byte_acc 53 | set byte_acc 0 54 | set bit_num 0 55 | } {if [expr $x == $width - 1] { 56 | set byte_acc [expr 8 - $width % 8] 57 | writechar $byte_acc 58 | set byte_acc 0 59 | set bit_num 0 60 | }} 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /oop.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Prototype-based object oriented LIL example. This file defines all the 3 | # functions needed for OOP declarations. See one of the oop_*.lil files 4 | # for example on how to use these functions. 5 | # 6 | 7 | func --obj-find-handler-- {obj msg} { 8 | set handler --obj-${obj}--m:${msg}-- 9 | if [reflect has-func $handler] { 10 | return $handler 11 | } { 12 | if [reflect has-global --obj-${obj}--parent--] { 13 | return [--obj-find-handler-- $"--obj-${obj}--parent--" $msg] 14 | } { 15 | return {} 16 | } 17 | } 18 | } 19 | 20 | func --obj-send-message-- {obj msg args} { 21 | set handler [--obj-find-handler-- $obj $msg] 22 | if not [streq $handler {}] { 23 | return [$handler $obj $msg $args] 24 | } 25 | return {} 26 | } 27 | 28 | func --obj-set-method-- {obj msg method} { 29 | set handler --obj-${obj}--m:${msg}-- 30 | func $handler {obj msg args} { 31 | return "[}$method{ $obj $args]" 32 | } 33 | } 34 | 35 | func --obj-set-parent-- {obj parent} { 36 | set global --obj-${obj}--parent-- $parent 37 | } 38 | 39 | func --obj-set-- args { 40 | set obj [index $args 1] 41 | set name [index $args 2] 42 | set realname --obj-${obj}--v:${name}-- 43 | if [expr [count $args] == 3] { 44 | return $$realname 45 | } { 46 | return [set global $realname [index $args 3]] 47 | } 48 | } 49 | 50 | func objset args { 51 | return [upeval "--obj-set-- \$self [slice $args 1]" 52 | } 53 | 54 | func method {obj msg args code} { 55 | set funcdecl "func {self" 56 | foreach $args { set funcdecl "$funcdecl $i" } 57 | set funcdecl "$funcdecl} {$code}" 58 | --obj-set-method-- $obj $msg [eval $funcdecl] 59 | } 60 | 61 | func new args { 62 | set parent [index $args 1] 63 | set obj [func args { 64 | return [--obj-send-message-- [index $args 0] [index $args 1] [slice $args 2]] 65 | }] 66 | if $parent { 67 | --obj-set-parent-- $obj $parent 68 | } 69 | --obj-send-message-- $obj init [slice $args 2] 70 | return $obj 71 | } 72 | 73 | func extend {old new} { 74 | --obj-set-parent-- $new $old 75 | } 76 | 77 | func typeof {obj} { 78 | return $"--obj-${obj}--parent--" 79 | } 80 | 81 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | lil 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | ?name? 14 | 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.autoBuildTarget 22 | all 23 | 24 | 25 | org.eclipse.cdt.make.core.buildArguments 26 | 27 | 28 | 29 | org.eclipse.cdt.make.core.buildCommand 30 | make 31 | 32 | 33 | org.eclipse.cdt.make.core.cleanBuildTarget 34 | clean 35 | 36 | 37 | org.eclipse.cdt.make.core.contents 38 | org.eclipse.cdt.make.core.activeConfigSettings 39 | 40 | 41 | org.eclipse.cdt.make.core.enableAutoBuild 42 | false 43 | 44 | 45 | org.eclipse.cdt.make.core.enableCleanBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.enableFullBuild 50 | true 51 | 52 | 53 | org.eclipse.cdt.make.core.fullBuildTarget 54 | all 55 | 56 | 57 | org.eclipse.cdt.make.core.stopOnError 58 | true 59 | 60 | 61 | org.eclipse.cdt.make.core.useDefaultBuildCmd 62 | true 63 | 64 | 65 | 66 | 67 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 68 | full,incremental, 69 | 70 | 71 | 72 | 73 | 74 | org.eclipse.cdt.core.cnature 75 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 76 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 77 | 78 | 79 | -------------------------------------------------------------------------------- /vim/lil.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: LIL 3 | " Maintainer: Kostas Michalopoulos 4 | " Last Change: 2011/08/07 5 | " Version: 1.0 6 | " URL: https://github.com/badsector/lil 7 | " 8 | " Loosely based on Vim's Tcl syntax file 9 | 10 | " For version 5.x: Clear all syntax items 11 | " For version 6.x: Quit when a syntax file was already loaded 12 | if version < 600 13 | syntax clear 14 | elseif exists("b:current_syntax") 15 | finish 16 | endif 17 | 18 | " Almost all LIL functions as defined in the lil.c file's register_stdcmds 19 | " function 20 | syn keyword lilFunction reflect func rename unusedname quote set local write print eval topeval 21 | syn keyword lilFunction upeval downeval enveval jaileval count index indexof filter list append slice 22 | syn keyword lilFunction subst concat foreach return expr inc dec read store if while for 23 | syn keyword lilFunction char charat codeat substr strpos length trim ltrim rtrim strcmp 24 | syn keyword lilFunction streq repstr split try error exit source lmap rand catcher 25 | 26 | " LIL Variables for $blah 27 | " syn match lilVarRef "$\(\([^;$[\]{}"' ]*\)\|\({[^}]*}\)\|\(\"[^\"]*\"\)\|\(\'[^\']*\'\)\)" 28 | syn match lilVarRef "\(${[^}]*}\)\|\($[^;$[\]{}"' ]*\)" 29 | 30 | " Line continuation 31 | syn match lilLineContinue '\\$' 32 | 33 | " Strings 34 | syn region lilEmbeddedRegion start='\[' end='\]' contained contains=lilVarRef 35 | syn region lilString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=lilVarRef,lilEmbeddedRegion 36 | syn region lilString start=+'+ end=+'+ skip=+\\\\\|\\'+ contains=lilVarRef,lilEmbeddedRegion 37 | "syn region lilString "'.*'" contains=lilEmbeddedRegion 38 | 39 | " Comments 40 | syn match lilComment "#.*$" 41 | 42 | " Special characters 43 | syn match lilSpecials "[{}[\]]" 44 | 45 | " Set keyword characters 46 | set iskeyword=@,48-57,_,-,192-255 47 | 48 | " Define the default highlighting. 49 | " For version 5.7 and earlier: only when not done already 50 | " For version 5.8 and later: only when an item doesn't have highlighting yet 51 | if version >= 508 || !exists("did_lil_syntax_inits") 52 | if version < 508 53 | let did_lil_syntax_inits = 1 54 | command -nargs=+ HiLink hi link 55 | else 56 | command -nargs=+ HiLink hi def link 57 | endif 58 | 59 | HiLink lilFunction Statement 60 | HiLink lilVarRef Identifier 61 | HiLink lilString String 62 | HiLink lilComment Comment 63 | HiLink lilSpecials Special 64 | 65 | delcommand HiLink 66 | endif 67 | 68 | let b:current_syntax = "lil" 69 | 70 | " vim: ts=8 noet 71 | -------------------------------------------------------------------------------- /sm.lil: -------------------------------------------------------------------------------- 1 | # 2 | # A simple state machine implementation in LIL. The implementation uses LIL's 3 | # reflection to check for state changes and possible transitions. 4 | # 5 | # The following article explains the ideas behind this code: 6 | # http://badsector.posterous.com/a-flexible-and-simple-script-driven-state-mac 7 | # 8 | # See also robot.lil for using these functions 9 | # 10 | 11 | # creates a new state machine 12 | func sm:new {type obj init} { 13 | set prefix [unusedname statemachine] 14 | set global $prefix [list $type $obj $init] 15 | return $prefix 16 | } 17 | 18 | # returns the type of the state machine 19 | func sm:type {sm} { 20 | return [index $$sm 0] 21 | } 22 | 23 | # returns the object of the state machine 24 | func sm:obj {sm} { 25 | return [index $$sm 1] 26 | } 27 | 28 | # returns the state of the state machine 29 | func sm:state {sm} { 30 | return [index $$sm 2] 31 | } 32 | 33 | # sets the state name 34 | func sm:-setstate {sm state} { 35 | set global $sm [list [index $$sm 0] [index $$sm 1] $state] 36 | } 37 | 38 | # transitions from the state machine's current state to the given state 39 | func sm:transit {sm to} { 40 | set type [sm:type $sm] 41 | set from [sm:state $sm] 42 | if [reflect has-func ${type}-${to}-check] { 43 | if not [${type}-${to}-check $sm] { return 0 } 44 | } 45 | if [reflect has-func ${type}-${from}-exit] { ${type}-${from}-exit $sm } 46 | sm:-setstate $sm $to 47 | if [reflect has-func ${type}-${to}-enter] { ${type}-${to}-enter $sm } 48 | return 1 49 | } 50 | 51 | # declares a new state function. This is just a shortcut for 52 | # declaring -- functions 53 | func sm:func {name args states} { 54 | set i 0 55 | set statec [count $states] 56 | while {$i < $statec - 1} { 57 | set subname [index $states $i] ; inc i 58 | set subcode [index $states $i] ; inc i 59 | func ${name}-${subname} "obj $args" $subcode 60 | } 61 | func $name {args} { return [eval "sm:call [index $args 1] "}$name{" [sm:obj [index $args 1]] [slice $args 2]"] } 62 | } 63 | 64 | # calls a state function. You don't really need that since it 65 | # is used by the function caller declared by sm:func 66 | func sm:call {args} { 67 | set sm [index $args 1] 68 | set name [index $args 2] 69 | set fargs [slice $args 3] 70 | set state [sm:state $sm] 71 | if [reflect has-func "${name}-${state}"] { 72 | return [eval "${name}-${state} $fargs"] 73 | } 74 | if [reflect has-func "${name}-default"] { 75 | return [eval "${name}-default $fargs"] 76 | } 77 | error "There is no state $state for state function $name of type $type" 78 | } 79 | 80 | -------------------------------------------------------------------------------- /catcher.lil: -------------------------------------------------------------------------------- 1 | # 2 | # Test for the 'catcher' function. The catcher function can be used to call 3 | # some code when an unknown function is called so that the script can 'catch' 4 | # unknown calls. It can be used to implement shell-like behavior or write small 5 | # mini/local languages for a specific purpose. 6 | # 7 | 8 | ############################################################################## 9 | # Set a catcher that will print the command and its arguments. The catcher will 10 | # receive the command and arguments in an 'args' list, like if an anonymous 11 | # function without arguments was specified. 12 | 13 | print "Catcher test 1" 14 | 15 | catcher {print $args} 16 | 17 | # Try some commands 18 | print "This will be printed just fine" 19 | foo bar 20 | etc 21 | this will not be printed 22 | however substitution is still done [expr 3 + 3] 23 | "since a list is what is displayed, this will appear in braces" 24 | 25 | ############################################################################## 26 | # Define a set of functions which define a mini language. The catcher is used 27 | # to delegate the call to the proper function. In this example the functions 28 | # just print what they do. The catcher is only set temporary from the parsecfg 29 | # function (which is supposed to parse some sort of configuration script) and 30 | # reset to the previous catcher before the function ends. 31 | 32 | print "Catcher test 2" 33 | 34 | set level 0 35 | 36 | func print-level {} { 37 | for {set i 0} {$i < $level} {inc i} {write " "} 38 | } 39 | 40 | func add-field {name values} { 41 | set previous-field $last-field 42 | set global last-field $name 43 | print-level 44 | print "Adding field $last-field" 45 | inc level 46 | eval $values 47 | dec level 48 | set global last-field $previous-field 49 | } 50 | 51 | func set-attribute {name value} { 52 | print-level 53 | print "Adding attribute '${name}' with value '${value}' to the field $last-field" 54 | } 55 | 56 | func parsecfg {cfg} { 57 | set prev_catcher [catcher] 58 | 59 | catcher { 60 | set name [index $args 0] 61 | set value [index $args 1] 62 | if [streq [charat $name 0] .] { 63 | set-attribute $name $value 64 | } { 65 | add-field $name $value 66 | } 67 | } 68 | 69 | eval $cfg 70 | 71 | catcher $prev_catcher 72 | } 73 | 74 | print "We'll try to parse" 75 | 76 | parsecfg { 77 | user { 78 | .name "Kostas Michalopoulos" 79 | .email badsector@runtimelegend.com 80 | .www none 81 | .nick "Bad Sector" 82 | groups { 83 | .group coder 84 | .group maintainer 85 | } 86 | .flags [expr 3 + 3 + 0] # this will be parsed as ".flags 6" 87 | } 88 | groups { 89 | group { 90 | .name coder 91 | .info "LIL Coders" 92 | .cando stuff 93 | } 94 | group { 95 | .name maintainer 96 | .info "LIL Maintainers" 97 | .cando otherstuff 98 | } 99 | } 100 | } 101 | 102 | Done # The previous catcher will be restored so this will display "Done!" 103 | 104 | ############################################################################## 105 | # Remove catchers, etc. An empty string will remove the current catcher and 106 | # lil will report unknown function calls like previously ( 107 | 108 | print "Catcher test 3" 109 | 110 | catcher {} 111 | 112 | "This will fail" 113 | And this will never be executed 114 | 115 | -------------------------------------------------------------------------------- /lil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LIL - Little Interpreted Language 3 | * Copyright (C) 2010-2012 Kostas Michalopoulos 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any damages 7 | * arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any purpose, 10 | * including commercial applications, and to alter it and redistribute it 11 | * freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you must not 14 | * claim that you wrote the original software. If you use this software 15 | * in a product, an acknowledgment in the product documentation would be 16 | * appreciated but is not required. 17 | * 2. Altered source versions must be plainly marked as such, and must not be 18 | * misrepresented as being the original software. 19 | * 3. This notice may not be removed or altered from any source distribution. 20 | * 21 | * Kostas Michalopoulos 22 | */ 23 | 24 | #ifndef __LIL_H_INCLUDED__ 25 | #define __LIL_H_INCLUDED__ 26 | 27 | #define LIL_VERSION_STRING "0.1" 28 | 29 | #define LIL_SETVAR_GLOBAL 0 30 | #define LIL_SETVAR_LOCAL 1 31 | #define LIL_SETVAR_LOCAL_NEW 2 32 | #define LIL_SETVAR_LOCAL_ONLY 3 33 | 34 | #define LIL_CALLBACK_EXIT 0 35 | #define LIL_CALLBACK_WRITE 1 36 | #define LIL_CALLBACK_READ 2 37 | #define LIL_CALLBACK_STORE 3 38 | #define LIL_CALLBACK_SOURCE 4 39 | #define LIL_CALLBACK_ERROR 5 40 | #define LIL_CALLBACK_SETVAR 6 41 | #define LIL_CALLBACK_GETVAR 7 42 | 43 | #if defined(LILDLL) && (defined(WIN32) || defined(_WIN32)) 44 | #ifdef __LIL_C_FILE__ 45 | #define LILAPI __declspec(dllexport __stdcall) 46 | #else 47 | #define LILAPI __declspec(dllimport __stdcall) 48 | #endif 49 | #define LILCALLBACK __declspec(__stdcall) 50 | #else 51 | #define LILAPI 52 | #define LILCALLBACK 53 | #endif 54 | 55 | #ifdef LILINT_LONGLONG 56 | typedef long long int lilint_t; 57 | #else 58 | #ifdef LILINT_INT64 59 | typedef __int64 lilint_t; 60 | #else 61 | #ifndef LILINT_CUSTOM 62 | #include 63 | typedef int64_t lilint_t; 64 | #endif 65 | #endif 66 | #endif 67 | 68 | typedef struct _lil_value_t* lil_value_t; 69 | typedef struct _lil_func_t* lil_func_t; 70 | typedef struct _lil_var_t* lil_var_t; 71 | typedef struct _lil_env_t* lil_env_t; 72 | typedef struct _lil_list_t* lil_list_t; 73 | typedef struct _lil_t* lil_t; 74 | typedef LILCALLBACK lil_value_t (*lil_func_proc_t)(lil_t lil, size_t argc, lil_value_t* argv); 75 | typedef LILCALLBACK void (*lil_exit_callback_proc_t)(lil_t lil, lil_value_t arg); 76 | typedef LILCALLBACK void (*lil_write_callback_proc_t)(lil_t lil, const char* msg); 77 | typedef LILCALLBACK char* (*lil_read_callback_proc_t)(lil_t lil, const char* name); 78 | typedef LILCALLBACK char* (*lil_source_callback_proc_t)(lil_t lil, const char* name); 79 | typedef LILCALLBACK void (*lil_store_callback_proc_t)(lil_t lil, const char* name, const char* data); 80 | typedef LILCALLBACK void (*lil_error_callback_proc_t)(lil_t lil, size_t pos, const char* msg); 81 | typedef LILCALLBACK int (*lil_setvar_callback_proc_t)(lil_t lil, const char* name, lil_value_t* value); 82 | typedef LILCALLBACK int (*lil_getvar_callback_proc_t)(lil_t lil, const char* name, lil_value_t* value); 83 | typedef LILCALLBACK void (*lil_callback_proc_t)(void); 84 | 85 | LILAPI lil_t lil_new(void); 86 | LILAPI void lil_free(lil_t lil); 87 | 88 | LILAPI int lil_register(lil_t lil, const char* name, lil_func_proc_t proc); 89 | 90 | LILAPI lil_value_t lil_parse(lil_t lil, const char* code, size_t codelen, int funclevel); 91 | LILAPI lil_value_t lil_parse_value(lil_t lil, lil_value_t val, int funclevel); 92 | 93 | LILAPI void lil_callback(lil_t lil, int cb, lil_callback_proc_t proc); 94 | 95 | LILAPI void lil_set_error(lil_t lil, const char* msg); 96 | LILAPI void lil_set_error_at(lil_t lil, size_t pos, const char* msg); 97 | LILAPI int lil_error(lil_t lil, const char** msg, size_t* pos); 98 | 99 | LILAPI const char* lil_to_string(lil_value_t val); 100 | LILAPI double lil_to_double(lil_value_t val); 101 | LILAPI lilint_t lil_to_integer(lil_value_t val); 102 | LILAPI int lil_to_boolean(lil_value_t val); 103 | 104 | LILAPI lil_value_t lil_alloc_string(const char* str); 105 | LILAPI lil_value_t lil_alloc_double(double num); 106 | LILAPI lil_value_t lil_alloc_integer(lilint_t num); 107 | LILAPI void lil_free_value(lil_value_t val); 108 | 109 | LILAPI lil_value_t lil_clone_value(lil_value_t src); 110 | LILAPI int lil_append_char(lil_value_t val, char ch); 111 | LILAPI int lil_append_string(lil_value_t val, const char* s); 112 | LILAPI int lil_append_val(lil_value_t val, lil_value_t v); 113 | 114 | LILAPI lil_list_t lil_alloc_list(void); 115 | LILAPI void lil_free_list(lil_list_t list); 116 | LILAPI void lil_list_append(lil_list_t list, lil_value_t val); 117 | LILAPI size_t lil_list_size(lil_list_t list); 118 | LILAPI lil_value_t lil_list_get(lil_list_t list, size_t index); 119 | LILAPI lil_value_t lil_list_to_value(lil_list_t list, int do_escape); 120 | 121 | LILAPI lil_list_t lil_subst_to_list(lil_t lil, lil_value_t code); 122 | LILAPI lil_value_t lil_subst_to_value(lil_t lil, lil_value_t code); 123 | 124 | LILAPI lil_env_t lil_alloc_env(lil_env_t parent); 125 | LILAPI void lil_free_env(lil_env_t env); 126 | LILAPI lil_env_t lil_push_env(lil_t lil); 127 | LILAPI void lil_pop_env(lil_t lil); 128 | 129 | LILAPI lil_var_t lil_set_var(lil_t lil, const char* name, lil_value_t val, int local); 130 | LILAPI lil_value_t lil_get_var(lil_t lil, const char* name); 131 | LILAPI lil_value_t lil_get_var_or(lil_t lil, const char* name, lil_value_t defvalue); 132 | 133 | LILAPI lil_value_t lil_eval_expr(lil_t lil, lil_value_t code); 134 | LILAPI lil_value_t lil_unused_name(lil_t lil, const char* part); 135 | 136 | LILAPI lil_value_t lil_arg(lil_value_t* argv, size_t index); 137 | 138 | LILAPI void lil_set_data(lil_t lil, void* data); 139 | LILAPI void* lil_get_data(lil_t lil); 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LIL - Little Interpreted Language 3 | * Copyright (C) 2010 Kostas Michalopoulos 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any damages 7 | * arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any purpose, 10 | * including commercial applications, and to alter it and redistribute it 11 | * freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you must not 14 | * claim that you wrote the original software. If you use this software 15 | * in a product, an acknowledgment in the product documentation would be 16 | * appreciated but is not required. 17 | * 2. Altered source versions must be plainly marked as such, and must not be 18 | * misrepresented as being the original software. 19 | * 3. This notice may not be removed or altered from any source distribution. 20 | * 21 | * Kostas Michalopoulos 22 | */ 23 | 24 | #define _BSD_SOURCE 25 | #ifndef WIN32 26 | #include 27 | #endif 28 | #ifdef __MINGW32__ 29 | /* allow the definition of popen, etc */ 30 | #undef __STRICT_ANSI__ 31 | #endif 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "lil.h" 37 | 38 | static int running = 1; 39 | static int exit_code = 0; 40 | 41 | static LILCALLBACK void do_exit(lil_t lil, lil_value_t val) 42 | { 43 | running = 0; 44 | exit_code = (int)lil_to_integer(val); 45 | } 46 | 47 | static char* do_system(size_t argc, char** argv) 48 | { 49 | #if defined(WIN32) || defined(WATCOMC) 50 | return NULL; 51 | #else 52 | char* cmd = NULL; 53 | int cmdlen = 0; 54 | size_t i; 55 | FILE* p; 56 | for (i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | LIL: A Little Interpreted Language 2 | ================================== 3 | 4 | 5 | 0. Contents 6 | ----------- 7 | 1. About 8 | 2. LIL syntax 9 | 3. LIL functions 10 | 3.1. Standard LIL functions 11 | 3.2. Command line interpreter LIL functions 12 | 4. Integrating LIL in C programs 13 | 4.1. Initialize LIL 14 | 4.2. Execute LIL code 15 | 4.3. Raise an error and obtain information about errors 16 | 4.4. Convert values between C and LIL 17 | 4.5. Register native functions 18 | 4.6. Other LIL library functions 19 | 4.7. LIL callback summary 20 | 4.8. Using LIL as a DLL 21 | 5. Integrating LIL in non-C programs 22 | 6. Contact 23 | 24 | 25 | 1. About 26 | -------- 27 | LIL (Little Interpreted Language) is a small C library in just a pair of 28 | .c and .h files which provide a compact yet very dynamic scripting 29 | language inspired by Tcl and the UNIX shell. LIL can be used in a wide 30 | range of situations, from simple configuration files to full extendability 31 | via scripting. 32 | 33 | The source code of LIL consists of a pair of .c and .h files (lil.c and 34 | lil.h) of ANSI C90 with some extensions from C99 (mostly the use of 64bit 35 | integers) which most modern compilers provide. The code has been tested to 36 | compile and work with the following compilers: 37 | 38 | * GNU C/C++ Compiler 3.x and 4.x 39 | * OpenWatcom C/C++ Compiler 1.9 40 | * LLVM Clang 41 | * Digital Mars C/C++ Compiler 8.42n 42 | * Tiny C Compiler 0.9.25 43 | * Microsoft Visual C++ 2010 Express (see below for older versions) 44 | * Borland's free C/C++ Compiler 5.5.1 (needs special Makefile) 45 | 46 | Users of older versions of Microsoft Visual C++ need to use a stdint.h 47 | file provided by external sources. A commonly used one stdint.h file for 48 | MSVC is http://msinttypes.googlecode.com/svn/trunk/stdint.h. Alternatively 49 | the global macro LILINT_INT64 can be used so that LIL will use __int64 for 50 | integers instead of stdint.h's int64_t. 51 | 52 | If the compiler doesn't use long long int nor __int64 for 64bit integers, 53 | then the global macro LILINT_CUSTOM must be defined and a type definition 54 | for lilint_t must exist before the inclusion of lil.h (including inside the 55 | lil.c file). 56 | 57 | As a side note, LIL has nothing to do with the "Little Implementation 58 | Language" for PDP (which i learned about months after i chose the name 59 | LIL for my library). Apparently that LIL was made during the same time as 60 | the UNIX system and the C language by P.J. Plauger. If you are interested 61 | in this historical language you can read about it here: 62 | 63 | http://www.ultimate.com/phil/lil/ 64 | 65 | 66 | 2. LIL syntax 67 | ------------- 68 | The syntax of LIL is very simple: the script is made up of "commands" 69 | and each command is a series of "words" separated by space, like: 70 | 71 | word1 word2 word3 ... wordn 72 | 73 | Words can be enclosed in quotes, double quotes and brackets which allow 74 | for special handling. Quotes and double quotes, for example, can be used 75 | to include spaces or special characters (by escaping them with the \ 76 | prefix as in C). Square brackets are used to call inline commands and 77 | substitute the inlined command with its result. Curly brackets are used 78 | to refer to a string without further processing (except counting the 79 | brackets inside them so that they can be nested). A dollar in front of 80 | a word will replace itself and the word with the value of the variable 81 | that has the same name as the word (or with nothing if there is no such 82 | variable). 83 | 84 | When LIL needs to execute a command, it looks for a function with the 85 | same name as the first word of the command. The function is executed 86 | using the rest of the words as its arguments (or parameters). For example 87 | the following command 88 | 89 | print hello fred 90 | 91 | will execute the function "print" using the two words "hello" and "fred" 92 | as the first and second argument. Using quotes one can combine the two 93 | words like 94 | 95 | print "hello fred" 96 | 97 | in which case LIL will execute the function "print" with the single word 98 | "hello fred" (note that a "word" in LIL can have any character, including 99 | spaces and even special characters by escaping them). Since the words are 100 | separated before LIL decides which is function and which not, technically 101 | you can use functions with spaces, like 102 | 103 | "hello fred" print 104 | 105 | which will execute the function "hello fred" with the single word "print" 106 | as its argument. In practice this should be avoided, at least for names 107 | that the script writer will use directly. 108 | 109 | As mentioned above the quotes can be used to escape characters, so you 110 | can write 111 | 112 | print "hello \"fred\"" 113 | 114 | An alternative would be to use the single quotes (to avoid the need of 115 | using the escape character for double quotes) like 116 | 117 | print 'hello "fred"' 118 | 119 | or use curly braces like 120 | 121 | print {hello "fred"} 122 | 123 | Curly braces aren't always an alternative to single and double quotes: 124 | unlike them, curly braces do not do any further processing (except to 125 | count the curly braces inside so they can know where they end). So this 126 | command 127 | 128 | print {hello \"fred\"} 129 | 130 | will include the \ character while this command 131 | 132 | print 'hello \"fred\"' 133 | 134 | will not because \" will be converted to ". 135 | 136 | Quotted strings can contain escape characters. These are characters 137 | which you either can't use or special characters you can't (or don't want) 138 | to type in the code. As shown above, an escaped character starts with 139 | the \ character (the "escape character") and followed by another character 140 | which defines which character will be inserted at that point. The escape 141 | characters LIL recognizes as special characters are 142 | 143 | b - inserts the backspace character 144 | t - inserts the horizontal tab character 145 | n - inserts the newline character 146 | v - inserts the vertical tab character 147 | f - inserts the formfeed character 148 | r - inserts the carriage return character 149 | a - inserts the bell character 150 | 151 | any other character will be included as-is without the \ character. For 152 | example the string "hello\nworld" will insert a newline character between 153 | "hello" and "world". The string "is this good\?" will be equal to the 154 | string "is this good?" and the string "hello \[world\]" will be equal 155 | to "hello [world]" (however LIL will not try to evaluate "world" as a 156 | command - see below). 157 | 158 | As mentioned above, square braces are used to replace (substitute) the 159 | command inside them with the result of that command. In LIL this is used 160 | to access the result of a function. As an example consider mathematical 161 | expressions: LIL does not have special expression handling. To use math 162 | you have to type the expression as one or more arguments to the "expr" 163 | function which will combine all arguments, parse the expression as a 164 | single string and return the result. So the command 165 | 166 | expr 4 + 4 167 | 168 | will have the result "8". This result will not be shown anywhere - it is 169 | just the result of the command. To access this result you use the square 170 | brackets with some other command. For example to display the command with 171 | the print function use the expression inside the brackets like 172 | 173 | print [expr 4 + 4] 174 | 175 | this will print "8". Here LIL actually sees two words, not five: the first 176 | word is the "print" word and the second word is the result of the command 177 | inside the brackets: when LIL sees the brackets, it scans its contents for 178 | an inline command. Then it executes that command (which in turn might 179 | contain other inline commands) and considers the word as the executed 180 | command's result instead of the brackets' contents. Note that if you 181 | typed 182 | 183 | print expr 4 + 4 184 | 185 | the word would be "print", "expr", "4", "+", "4" and the print function 186 | would simply display "expr 4 + 4" because without the square brackets 187 | there is not any special meaning for "expr". 188 | 189 | A very important function for LIL (beyond expr) is the "set" function. 190 | This function can be used to set values to variables. For example when 191 | you execute 192 | 193 | set foo bar 194 | 195 | you set the value of the "foo" variable to the string "bar". As you might 196 | have guessed if type 197 | 198 | set "foo bar" "moo mew" 199 | 200 | you will set the value of the "foo bar" variable to the string "moo mew": 201 | LIL can use any valid character as a name, as long as you can express it 202 | as a string. The set function can be used with zero or more arguments. 203 | For each pair, a variable named as the first word of the pair will be set 204 | to the second word of the pair. If there is an odd number of arguments, 205 | the result of the set function is the value of the variable that has the 206 | same name as the last word. So for example the command 207 | 208 | set name 209 | 210 | will have a result equal with the value of the variable "name" and thus 211 | the command 212 | 213 | print [set name] 214 | 215 | will print the value of the variable "name". Since accessing variables is 216 | something very common LIL provides a shortcut: a dollar in front of a word 217 | is the same as calling set with that word as a single argument. So the 218 | command above could be written as 219 | 220 | print $name 221 | 222 | Note two important things however: first, the name of the variable is NOT 223 | "$name". It is "name". The dollar is used as a shortcut for "[set name]". 224 | And second, it *really* is a shortcut: the "set" function will be called 225 | even if you don't type it (so if you override it, the overridden function 226 | will be called). You can also change the behavior of $ by setting another 227 | function to be called with "reflect dollar-prefix" (see section 3 for 228 | details). 229 | 230 | Remember the part about curly brackets above? Well, if you type 231 | 232 | print "hello $user" 233 | 234 | the result will be to display "hello " followed with whatever the value of 235 | the variable "user" is (so for example if "user" was set to "fred" the 236 | displayed string would be "hello fred"). However if you type 237 | 238 | print {hello $user} 239 | 240 | the displayed string will be "hello $user" because curly brackets really 241 | do not process whatever is inside. This can be used to define new 242 | functions because the function's code is, like anything else in LIL, a 243 | plain old string. And since you don't want to process that string's 244 | contents directly, you need curly brackets. 245 | 246 | The definition of a new function is done using the "func" function. This 247 | function accepts zero or more arguments (when zero arguments are given, 248 | the function does nothing and returns an empty string). When three 249 | arguments are given (the most common case) they are considered as the name 250 | the argument list and the code/body of the function. For example 251 | 252 | func foo {a b} { print $a $b } 253 | 254 | defines a function named "foo" with the argument list "a b" and as code 255 | the string "print $a $b". The argument list is a LIL list (a space 256 | separated list of words using similar rules as the separation of words for 257 | commands - which in turn can include other sublists but escaping their 258 | words, etc - with the exception that a LIL list value can include newline 259 | characters) where each word in the list specifies an argument and the code 260 | is the code that will be executed when the function is evaluated. Before 261 | LIL evaluates a function, it stores in local variables with the same name 262 | as those specified in the argument list the arguments passed to the 263 | function in the same order as they appear in the argument list. So for 264 | example when evaluating the above function LIL will save the first 265 | argument passed to the function in "a" and the second argument in "b". If 266 | more arguments are given these are lost and if less arguments are given, 267 | the rest of the expected arguments are set to empty strings (so for 268 | example if "foo 32" is given the "b" variable will be an empty string). 269 | 270 | To use an unknown number of variables use the special name "args" as the 271 | only word in the argument list. LIL will store all passed arguments in 272 | the "args" argument as a list which you can access either directly or via 273 | the list functions (index, count, foreach, etc). For example: 274 | 275 | func foo args { foreach $args { print arg: $i } } 276 | 277 | which when used like 278 | 279 | foo apple orange cake 280 | 281 | will display 282 | 283 | arg: foo 284 | arg: apple 285 | arg: orange 286 | arg: cake 287 | 288 | (when the special "args" name is used, the first word in the list will 289 | always be the function's name) 290 | 291 | The "func" function can also be used with two or even one argument. 292 | This use allows the definition of anonymous (or actually, randomly named) 293 | functions. In the two arguments format, the first argument is the 294 | arguments list as previously and the second argument is the function's 295 | code. For example 296 | 297 | func {a b} { return [expr $a + $b] } 298 | 299 | returns an anonymous function which accepts two arguments and returns 300 | their sum. In the one argument format, the only argument is the 301 | function's code and the arguments are stored in the "args" variable as if 302 | you used the special "args" name. For example 303 | 304 | func { foreach $args { print $i is good } } 305 | 306 | returns an anonymous function which prints "... is good" for each one of 307 | the arguments LIL passes to it. 308 | 309 | So how are anonymous functions used? Remember the basic syntax of LIL 310 | 311 | word1 word2 word3 ... wordn 312 | 313 | and that that when LIL wants to execute the command the first word is the 314 | name of the function? Well, word1 is no different than word2, word3, etc 315 | and can be a variable reference too. So if you type 316 | 317 | set foo print 318 | $foo hello 319 | 320 | LIL will replace "$foo" with "print" as normal and then will execute the 321 | function "print" because that happens to be the first word. So you use 322 | anonymous functions in the same way: anonymous functions aren't really that 323 | anonymous but they have a generated name. That name is what "func" 324 | returns. So if you type 325 | 326 | set foo [func {a b} { return [expr $a + $b] }] 327 | print [$foo 3 2] 328 | 329 | LIL will define a randomly named function with the argument list "a b" and 330 | code "return [expr $a + $b]", set its random name to the "foo" variable 331 | and - in the next line - call it with the arguments 3 and 2 and pass the 332 | result to print which in turn will display it - "5". 333 | 334 | LIL itself does not require the use of anonymous functions, but they can 335 | be handy in more advanced scripts and situations. An example would be a 336 | function which returns another function which is composed using the 337 | arguments to the first function. 338 | 339 | When using functions you should keep in mind variable scope: variables 340 | are defined in global scope (visible and accessible from everywhere) and 341 | local scope. Local scope has variables defined from within the function 342 | itself. When you access a variable for reading it (like when using it 343 | with the dollar) LIL looks in the local environment (where the variables 344 | are stored) and then the global environment. When you use the "set" 345 | function to set the value of a variable LIL always look first in the 346 | local environment and if the variable isn't found, it looks in the global 347 | environment. If no variable is found, a new variable in the local 348 | environment will be created. To force a global variable to be set or 349 | created, put the special "global" word as the first argument to the set 350 | function, like 351 | 352 | set global level 32 353 | 354 | which sets the value of the global variable "level" to "32". Functions 355 | that create variables always provide this special "global" first argument 356 | to force the assignment of global variables. Note that the use of 357 | "global" is only needed for code that runs from functions. Code that is 358 | executed outside a function always uses the global environment. To 359 | force a local variable, you need to create an empty local variable first 360 | by calling the "local" function, like 361 | 362 | local level 363 | set level 32 364 | 365 | which first creates a local variable (even if a global with the same name 366 | exists) with an empty value and then it sets its value to 32 (since the 367 | set function first looks in the local environment, it will find the one 368 | just made and will ignore any variable that may be in the global one). 369 | 370 | The last note on LIL's syntax is word concatenation. This is really 371 | simple (and technically is not concatenation at all but it is easier to 372 | think it like this): if two words are not separated by space they are 373 | combined to a single word. So for example the command 374 | 375 | print "hello "world 376 | 377 | is made up of two words: "print" and "hello world". Similarly the command 378 | 379 | print "is it "[expr 3 + 2]? 380 | 381 | is made up of two words again: "print" and "is it six?". This happens 382 | because the "is it ", [expr 3 + 2] and ? parts are combined together and 383 | not separated by a space. 384 | 385 | LIL commands are separated by newlines (each command takes a whole line) 386 | or the ; character. For example, for LIL the code 387 | 388 | print hello ; print world 389 | 390 | is the same as 391 | 392 | print hello 393 | print world 394 | 395 | Finally you can put comments in the code using the # character. Any 396 | characters after # until the end of the line will be ignored by the LIL 397 | interpreter. 398 | 399 | 400 | For more information and details on LIL's syntax, check the .lil example 401 | files that come with the source code distribution. And of course the C 402 | code itself is clean and compact which makes it easy to read and, if 403 | needed, modify. 404 | 405 | 3. LIL functions 406 | ---------------- 407 | 408 | 3.1. Standard LIL functions 409 | ---------------------- 410 | 411 | Here is a summary of the functions that LIL provides by default to all 412 | LIL scripts (in order of appearance in the lil.c file): 413 | 414 | reflect 415 | reflect information about the LIL runtime and the program 416 | 417 | reflect version 418 | returns the LIL_VERSION_STRING 419 | 420 | reflect args 421 | returns a list with the argument names for the given function 422 | 423 | reflect body 424 | returns the code of the given function 425 | 426 | reflect func-count 427 | returns the number of the known functions 428 | 429 | reflect funcs 430 | returns a list with all the known function names 431 | 432 | reflect vars 433 | returns a list with all the known variable names (includes global 434 | and local variables) 435 | 436 | reflect globals 437 | returns a list with all the known global variable names 438 | 439 | reflect has-func 440 | returns a true value (non-zero, non-empty value) if a function with 441 | the given name is known 442 | 443 | reflect has-var 444 | returns a true value (non-zero, non-empty value) if a variable with 445 | the given name is known 446 | 447 | reflect has-global 448 | returns a true value (non-zero, non-empty value) if a global 449 | variable with the given name is known 450 | 451 | reflect error 452 | returns the last error message or an empty string if there is no 453 | error condition active (this is usually used with the try function) 454 | 455 | reflect dollar-prefix [prefix] 456 | if [prefix] is specified, then this changes the dollar prefix. If no 457 | arguments are given, the current dollar prefix is returned. The dollar 458 | prefix is the command to be executed for dollar expansions (like $foo). 459 | The word after the dollar prefix is appended immediately after the 460 | prefix and the whole is executed. The default dollar prefix is 'set ' 461 | (notice the space which will separate the call to "set" from the word 462 | following) 463 | 464 | reflect this 465 | returns the code of the current local environment. This will return 466 | the currently executed function's body, the current root (top-level) 467 | code or the current catcher code (if the current environment is a 468 | catcher environment) 469 | 470 | reflect name 471 | returns the name of the currently executed function or an empty string 472 | if the code is executed at root level (or the name of the current 473 | function is unknown) 474 | 475 | func [name] [argument list | "args"] 476 | register a new function. See the section 2 for more information 477 | 478 | rename 479 | rename an existing function. Note that the "set" function is used to 480 | access variables using the $ prefix so if the "set" function is 481 | renamed, variables will only be accessible using the new name. The 482 | function returns the 483 | 484 | unusedname [part] 485 | return an unused function name. This is a random name which has the 486 | form !!un![part]!!nu!!. The [part] is optional (if not 487 | provided "unusedname" will be used) 488 | 489 | quote [...] 490 | return the arguments as a single space-separated string 491 | 492 | set ["global"] [name [value] ...] 493 | set the variable "name" to the "value". If there is an odd number of 494 | arguments, the function returns the value of the variable which has 495 | the same name as the last argument. Otherwise an empty value is 496 | returned. See section 2 for details 497 | 498 | local [...] 499 | make each variable defined in the arguments a local one. If the 500 | variable is already defined in the local environment, nothing is done. 501 | Otherwise a new local variable will be introduced. This is useful 502 | for reusable functions that want to make sure they will not modify 503 | existing global variables 504 | 505 | write [...] 506 | write the arguments separated by spaces to the program output. By 507 | default this is the standard output but a program can override this 508 | using the LIL_CALLBACK_WRITE callback 509 | 510 | print [...] 511 | like write but adds a newline at the end 512 | 513 | eval [...] 514 | combines the arguments to a single string and evaluates it as LIL 515 | code. The function returns the result of the LIL code 516 | 517 | topeval [...] 518 | combines the arguments to a single string and evaluates it as LIL 519 | code in the topmost (global) environment. This can be used to execute 520 | code outside of any function's environment that affects the global 521 | one 522 | 523 | upeval [...] 524 | combines the arguments to a single string and evaluates it as LIL 525 | code in the environment above the current environment (the parent 526 | environment). For functions this is usually the function caller's 527 | environment. This can be used to access local variables (for read 528 | and write purposes) of a function's caller or to affect its flow 529 | (like causing a caller function to return). The function can be 530 | used to provide most of the functionality that other languages 531 | provide via the use of macros but at the program's runtime and with 532 | full access to the program's state 533 | 534 | downeval [...] 535 | downeval complements upeval. It works like eval, but the code is 536 | evaluated in the environment where the most recent call to upeval was 537 | made. This also works with topeval 538 | 539 | enveval [invars] [outvars] 540 | the will be executed in its own environment. The environment 541 | will be similar to a function's environment. If invars is provided, 542 | it is assumed to be a list with variable names to be copied from the 543 | current environment to the new environment. If outvars is provided, it 544 | is assumed to be a list with variable names to be copied from the new 545 | environment back to the current one (global variables will remain 546 | global). If invars is provided but not outvars, the variables in 547 | invars will be copied back as if outvars was provided with the same 548 | variable names. To make the variables "one way" (that is, to copy 549 | nothing back) just use an empty list for the outvars argument. From 550 | inside enveval both return and an immediate value can be used to 551 | return a value. Calling return will not cause the calling function 552 | to exit 553 | 554 | jaileval ["clean"] 555 | the will be executed in its own LIL runtime. Unless "clean" 556 | is specified, the new LIL runtime will get a copy of the currently 557 | registered native functions. The can use "return" to return 558 | a value (which is returned by jaileval) 559 | 560 | count 561 | returns the number of items in a LIL list 562 | 563 | index 564 | returns the -th item in a LIL list. The indices begin from 565 | zero (so 0 is the first index, 1 is the second, etc) 566 | 567 | indexof 568 | returns the index of the first occurence of in a LIL list. If 569 | the does not exist indexof will return an empty string. The 570 | indices begin from zero (so 0 is the first index, 1 is the second, 571 | etc) 572 | 573 | filter [varname] 574 | filters the given list by evaluating the given expression for each 575 | item in the list. If the expression equals to true (is a non-zero 576 | number and a non-empty string), then the item passes the filter. 577 | Otherwise the filtered list will not include the item. For each 578 | evaluation, the item's value is stored in the [varname] variable 579 | (or in the "x" variable if no [varname] was given). The function 580 | returns the filtered list 581 | 582 | list [...] 583 | returns a list with the arguments as its items 584 | 585 | append ["global"] 586 | appends the value to the variable containing the 587 | list (or creates it if the variable is not defined). If the "global" 588 | special word is used, the list variable is assumed to be a global 589 | variable 590 | 591 | slice [to] 592 | returns a slice of the given list from the index to the index 593 | [to]-1 (that is, the [to]-th item is not includd). The indices are 594 | clamped to be within the 0.. range. If [to] is not 595 | given, the slice contains all items from the index up to the 596 | end of the list 597 | 598 | subst [...] 599 | perform string substitution to the arguments. For example the code 600 | 601 | set foo bar 602 | set str {foo$foo} 603 | print [substr $str] 604 | 605 | will print "foobar" 606 | 607 | concat [...] 608 | substitutes each argument as a list, converts it to a string and 609 | returns all strings combined into one 610 | 611 | foreach [name] 612 | for each item in the list, stores it to a variable named "i" 613 | and evalues the code in . If [name] is provided, this will be 614 | used instead of "i". The results of all evaluations are stored in a 615 | list which is returned by the function 616 | 617 | return [value] 618 | stops the execution of a function's code and uses as the 619 | result of that function (note that normally the result of a function 620 | is the result of the last command of that function). The result of 621 | return is always the passed value 622 | 623 | result [value] 624 | sets or returns the current result value of a function but unlike 625 | the return function, it doesn't stop the execution. If no argument 626 | is given, the function simply returns the current result value - if 627 | no previous call to result was made, then this will return an empty 628 | value even if other calls were made previously. The result of this 629 | function when an argument is given, is simply the given argument 630 | itself 631 | 632 | expr [...] 633 | combines all arguments into a single string and evaluates the 634 | mathematical expression in that string. The expression can use the 635 | following operators (in the order presented): 636 | 637 | (a) - parentheses 638 | 639 | -a - negative sign 640 | +a - positive sign 641 | ~a - bit inversion 642 | !a - logical negation 643 | 644 | a * b - multiplication 645 | a / b - floating point division 646 | a \ b - integer division 647 | a % b - modulo 648 | 649 | a + b - addition 650 | a - b - subtraction 651 | 652 | a << b - bit shifting 653 | a >> b 654 | 655 | a <= b - comparison 656 | a >= b 657 | a < b 658 | a > b 659 | 660 | a == b - equality comparison 661 | or 662 | a != b 663 | 664 | a & b - bitwise AND 665 | 666 | a || b - logical OR 667 | a && b - logical AND 668 | 669 | inc [value] 670 | numerically add [value] to the variable "name". If [value] is not 671 | provided, 1 will be added instead 672 | 673 | dec [value] 674 | numerically subtract [value] to the variable "name". If [value] is 675 | not provided, 1 will be subtracted instead 676 | 677 | read 678 | reads and returns the contents of the file . By default LIL 679 | will look for the file in the host program's current directory, but 680 | the program can override this using LIL_CALLBACK_READ. If the 681 | function failed to read the file it returns an empty value (note, 682 | however than a file can also be empty by itself) 683 | 684 | store 685 | stores the value in the file . By default LIL will 686 | create the file in the host program's current directory, but the 687 | program can override ths using LIL_CALLBACK_STORE. The function will 688 | always return 689 | 690 | if ["not"] [else-code] 691 | if value evaluates to true (non-zero, non-empty string), LIL 692 | will evaluate the code in . Otherwise (and if provided) the 693 | code in [else-code] will be evaluated. If the "not" special word is 694 | used, the check will be reversed. The function returns the result of 695 | whichever code is evaluated 696 | 697 | while ["not"] 698 | as long as evaluates to a true (or false if "not" is used) 699 | value, LIL will evaluate . The function returns the last 700 | result of the evaluation of or an empty value if no 701 | evaluation happened (note, however that the last evaluation can 702 | also return an empty value) 703 | 704 | for 705 | the loop will begin by evaluating the code in normally. Then 706 | as long as the expression evaluates to a true value, the 707 | code in will be evaluated followed by the code in . The 708 | function returns the result of the last evaluation of 709 | 710 | char 711 | returns the character with the given code as a string. Note that the 712 | character 0 cannot be used in the current implementation of LIL since 713 | it depends on 0-terminated strings. If 0 is passed, an empty string 714 | will be returned instead 715 | 716 | charat 717 | returns the character at the given index of the given string. The index 718 | begins with 0. If an invalid index is given, an empty value will be 719 | returned 720 | 721 | codeat 722 | returns the character code at the given index of the given string. The 723 | index begins with 0. If an invalid index is given, an empty value will 724 | be returned 725 | 726 | substr [length] 727 | returns the part of the given string beginning from and for 728 | [length] characters. If [length] is not given, the function will 729 | return the string from to the end of the string. The indices 730 | will be clamped to be within the string boundaries 731 | 732 | strpos [start] 733 | returns the index of the string in the string . If 734 | [start] is provided, the search will begin from the character at 735 | [start], otherwise it will begin from the first character. If the 736 | part is not found, the function will return -1 737 | 738 | length [...] 739 | the function will return the sum of the length of all arguments 740 | 741 | trim [characters] 742 | removes any of the [characters] from the beginning and ending of a 743 | string until there are no more such characters. If the [characters] 744 | argument is not given, the whitespace characters (space, linefeed, 745 | newline, carriage return, horizontal tab and vertical tab) are used 746 | 747 | ltrim [characters] 748 | like "trim" but removes only the characters from the left side of the 749 | string (the beginning) 750 | 751 | rtrim [characters] 752 | like "trim" but removes only the characters from the right side of the 753 | string (the ending) 754 | 755 | strcmp 756 | compares the string and - if is lesser than a 757 | negative value will be returned, if is greater a positive an 758 | if both values are equal zero will be returned (this is just a 759 | wrap for C's strcmp() function) 760 | 761 | streq 762 | returns a true value if both strings are equal 763 | 764 | repstr 765 | returns the string with all occurences of replaced with 766 | 767 | 768 | split [sep] 769 | split the given string in substrings using [sep] as a separator and 770 | return a list with the substrings. If [sep] is not given, the space 771 | is used as the separator. If [sep] contains more than one characters, 772 | all of them are considered as separators (ie. if ", " is given, the 773 | string will be splitted in both spaces and commas). If [sep] is an 774 | empty string, the is returned unchanged 775 | 776 | try [handler] 777 | evaluates the code in normally and returns its result. If an 778 | error occurs while the code in is executed, the execution 779 | stops and the code in [handler] is evaluated, in which case the 780 | function returns the result of [handler]. If [handler] is not 781 | provided the function returns 0 782 | 783 | error [msg] 784 | raises an error. If [msg] is given the error message is set to 785 | otherwise no error message is set. The error can be captured using 786 | the try function (see above) 787 | 788 | exit [code] 789 | requests from the host program to exit. By default LIL will call the 790 | C function exit() but the host program can override this using the 791 | LIL_CALLBACK_EXIT callback. If [code] is given it will be provided 792 | as a potential exit code (but the program can use another if it 793 | provides a LIL_CALLBACK_EXIT callback) 794 | 795 | source 796 | read and evaluate LIL source code from the file . The result 797 | of the function is the result of the code evaluation. By default LIL 798 | will look for a text file in the host program's current directory 799 | but the program can override that by using LIL_CALLBACK_SOURCE 800 | 801 | lmap [name2 [name3 ...]] 802 | map the values in the list to variables specified by the rest of the 803 | arguments. For example the command 804 | 805 | lmap [5 3 6] apple orange pear 806 | 807 | will assign 5 to variable apple, 3 to variable orange and 6 to 808 | variable pear 809 | 810 | rand 811 | returns a random number between 0.0 and 1.0 812 | 813 | catcher [code] 814 | sets, removes or returns the current catcher code. The code can be 815 | used to "catch" calls of unknown functions and is executed inside 816 | its own environment as if an anonymous function without specified 817 | arguments was called. This means that the code can access the name 818 | and the arguments of the function call using the "args" list - 819 | however unlike anonymous functions which get a random name, the zero 820 | index of the args list contains the unknown function's name. The 821 | code can also use "return" to return some value. If the catcher code 822 | calls an unknown function, it will be called again - however to avoid 823 | infinite loops a limit on the nested calls to the catcher code is set 824 | using the MAX_CATCHER_DEPTH constant (which by default is set to 825 | 16384). 826 | 827 | This function can be used to implement small embedded DSLs in LIL code 828 | or provide some sort of shell (as in UNIX shell) functionality by 829 | delegating the unknown function calls to some other function/command 830 | handler (like executing an external program). 831 | 832 | If catcher is called with an empty string, the catcher code is removed 833 | and LIL will resume raising errors when an unknown function is called 834 | (which is the default behavior before any call to catcher is made). 835 | 836 | If catcher is called without arguments it will return the current 837 | catcher code. This can be used to temporary save the current catcher 838 | code when changing the catcher code temporarily. For example 839 | 840 | set previous-catcher [catcher] 841 | catcher {print Call failed: $args} 842 | # do something 843 | catcher $previous-catcher 844 | 845 | When using catcher for DSLs it is recommended to save the previous 846 | catcher. For an example of catcher with comments see the catcher.lil 847 | source file. 848 | 849 | 3.2. Command line interpreter LIL functions 850 | -------------------------------------- 851 | The functions shown below are only available to the command line LIL 852 | interpreter (the "lil" executable). 853 | 854 | writechar code 855 | writes the character defined by the given code (usually ASCII code) 856 | to the standard output 857 | 858 | system 859 | executes the system command defined by and returns the data 860 | placed in the command's standard output 861 | 862 | readline 863 | reads a string from the standard input until the end of file or end 864 | of line mark/character is found and returns it 865 | 866 | 867 | 4. Integrating LIL in C programs 868 | -------------------------------- 869 | To integrate LIL in C programs you have two options: 870 | 871 | 1. Use the liblil.a library (for Clang and GCC) or liblil.lib (for 872 | OpenWatcom) as a static library from your project, or 873 | 874 | 2. Put the lil.c and lil.h files directly in your project 875 | 876 | Whichever method you choose, the rest is the same. Please note that 877 | the LIL interface should not be considered as frozen at this point. The 878 | library is under constant development and might change. In the future a 879 | frozen API will be provided but even that will only be guaranteed to 880 | survive major versions. 881 | 882 | 4.1. Initialize LIL 883 | -------------- 884 | You can have several "LILs" running: each one can be separate from the 885 | others and have its own definitions. A LIL runtime is stored in the lil_t 886 | C type that basically specifies an object. To construct a lil_t object 887 | use lil_new() and to destroy it use lil_free(). For example: 888 | 889 | lil_t lil = lil_new(); 890 | ... 891 | lil_free(lil); 892 | 893 | Before running LIL code you might want to override some of LIL's default 894 | functionality. This can be done using the lil_callback() function which 895 | has the following signature: 896 | 897 | void lil_callback(lil_t lil, 898 | int cb, 899 | lil_callback_proc proc) 900 | 901 | The cb is one of the LIL_CALLBACK_* constants defined in the lil.h file 902 | and the proc is a function with the same signature as the 903 | lil_callback_*_proc_t type defined in lil.h, casted back to 904 | lil_callback_proc_t. For example to define a callback for the "exit" 905 | function (something you probably want to do in most programs) use the 906 | following code 907 | 908 | void handl_exit(lil_t lil, lil_value_t arg) 909 | { 910 | ... 911 | } 912 | 913 | ... 914 | 915 | lil_callback(lil, LIL_CALLBACK_EXIT, (lil_callback_proc_t)handl_exit); 916 | 917 | 4.2. Execute LIL code 918 | ---------------- 919 | To execute LIL code use the lil_parse() function. This function has the 920 | following signature: 921 | 922 | lil_value_t lil_parse(lil_t lil, 923 | const char* code, 924 | size_t codelen, 925 | int funclevel) 926 | 927 | If 0 is given for codelen, LIL will simply use strlen for it. Funclevel 928 | should always be 1, unless the evaluated code is supposed to be executed 929 | inside the current environment. Setting funclevel to 1 will reset (clear) 930 | the breakrun flag (which is set by return to stop executing code in 931 | lil_parse, lil_parse_value and loops). 932 | 933 | The function will return a LIL value which must be released by calling 934 | lil_free_value(). The LIL value is the code's result. 935 | 936 | An alternative to lil_parse is lil_parse_value which can be used to 937 | parse code which is stored in a LIL value. The signature is 938 | 939 | lil_value_t lil_parse_value(lil_t lil, 940 | lil_value_t val, 941 | int funclevel) 942 | 943 | 4.3. Raise an error and obtain information about errors 944 | ---------------------------------------------- 945 | You can raise an error (similar to an exception but all errors in LIL 946 | are "united" under the same umbrella - runtime errors, syntax errors, etc) 947 | using the lil_set_error() function which has the following signature 948 | 949 | void lil_set_error(lil_t lil, 950 | const char* msg) 951 | 952 | where msg is the message of the error. The LIL script can use the "try" 953 | function to catch the error or, if the error is not catched, the host 954 | program can use lil_error() to obtain information about it. The 955 | lil_error() function will return a non-zero value if there is an error 956 | message available. The signature of the function is 957 | 958 | int lil_error(lil_t lil, 959 | const char** msg, 960 | size_t* pos) 961 | 962 | the msg pointer will receive the error message and pos will receive the 963 | position where the message occured (note that the position is usually 964 | local to the executed command, not the whole script). 965 | 966 | 4.4. Convert values between C and LIL 967 | -------------------------------- 968 | LIL uses the lil_value_t type for its own values. To convert from C to 969 | lil_value_t you use the following functions: 970 | 971 | lil_value_t lil_alloc_string(const char* str) 972 | lil_value_t lil_alloc_double(double num) 973 | lil_value_t lil_alloc_integer(lilint_t num) 974 | 975 | Note that "alloc" here really means allocate: the values will allocate 976 | memory on the heap for their contents. You are responsible for releasing 977 | the memory using lil_free_value() with the exception of function results 978 | (see next). 979 | 980 | To convert a lil_value_t to a C type use one of the following functions: 981 | 982 | const char* lil_to_string(lil_value_t val) 983 | double lil_to_double(lil_value_t val) 984 | lilint_t lil_to_integer(lil_value_t val) 985 | int lil_to_boolean(lil_value_t val) 986 | 987 | You can also clone a value using lil_clone_value() and append characters 988 | at the end of existing values using one of the following functions: 989 | 990 | lil_value_t lil_clone_value(lil_value_t src) 991 | int lil_append_char(lil_value_t val, char ch) 992 | int lil_append_string(lil_value_t val, const char* s) 993 | int lil_append_val(lil_value_t val, lil_value_t v) 994 | 995 | Using the following functions you can manipulate LIL lists: 996 | 997 | lil_list_t lil_alloc_list(void) 998 | void lil_free_list(lil_list_t list) 999 | void lil_list_append(lil_list_t list, lil_value_t val) 1000 | size_t lil_list_size(lil_list_t list) 1001 | lil_value_t lil_list_get(lil_list_t list, size_t index) 1002 | lil_value_t lil_list_to_value(lil_list_t list, int do_escape) 1003 | 1004 | the last function will convert a lil_list_t to a LIL value. Unless you are 1005 | sure that escaping is not needed, you should always use a non-zero value 1006 | for do_escape. The reverse can be performed with 1007 | 1008 | lil_list_t lil_subst_to_list(lil_t lil, lil_value_t code) 1009 | 1010 | and combining the two with 1011 | 1012 | lil_value_t lil_subst_to_value(lil_t lil, lil_value_t code) 1013 | 1014 | 4.5. Register native functions 1015 | ---------------------------- 1016 | To register a new function in LIL use the lil_register() function. This 1017 | function has the following signature: 1018 | 1019 | int lil_register(lil_t lil, 1020 | const char* name, 1021 | lil_func_proc_t proc) 1022 | 1023 | and returns a non-zero value if the registration was successful. The 1024 | native function must have the following signature: 1025 | 1026 | lil_value_t lil_func_proc(lil_t lil, 1027 | size_t argc, 1028 | lil_value_t* argv) 1029 | 1030 | where lil is the lil object that issued the function, argc is the number 1031 | of arguments used and argv is an array of "argc" lil_value_t elements with 1032 | the arguments passed to the function. The function must return a newly 1033 | allocated lil_value_t object or NULL if the function returns nothing (or 1034 | returns an empty string). 1035 | 1036 | An example: 1037 | 1038 | static lil_value_t fnc_hi(lil_t lil, size_t argc, lil_value_t* argv) 1039 | { 1040 | printf("Hi!\n"); 1041 | return NULL; 1042 | } 1043 | 1044 | ... 1045 | 1046 | lil_register(lil, "hi", fnc_hi); 1047 | 1048 | 4.6. Other LIL library functions 1049 | --------------------------- 1050 | Some other library functions are 1051 | 1052 | lil_var_t lil_set_var(lil_t lil, 1053 | const char* name, 1054 | lil_value_t val, 1055 | int local) 1056 | 1057 | which can be used to set a variable to a value. local must be one of 1058 | LIL_SETVAR_LOCAL, LIL_SETVAR_LOCAL_NEW, LIL_SETVAR_LOCAL_ONLY or 1059 | LIL_SETVAR_GLOBAL. Usually you need LIL_SETVAR_LOCAL or LIL_SETVAR_GLOBAL. 1060 | LIL_SETVAR_LOCAL_NEW will always allocate a new variable in the environment 1061 | and should be used with lil_push_env() and lil_pop_env(). See lil.c for 1062 | details on how to use these. 1063 | 1064 | LIL_SETVAR_LOCAL_ONLY will make sure that the variable is stored in the 1065 | local environment and can be used to avoid name collisions between variables 1066 | defined inside and outside functions. It should be used by functions that 1067 | set their own variables to be used by the scripts (for example, foreach uses 1068 | this to avoid name collisions between its index variable and the global 1069 | environment). When in doubt, use LIL_SETVAR_LOCAL if the variable's name is 1070 | provided by the script and the function is supposed to act on a variable, 1071 | otherwise use LIL_SETVAR_LOCAL_ONLY if the variable name is decided by the 1072 | function (with optional alteration of the name by the script, such as in 1073 | foreach) and the variable is to be reused (so LIL_SETVAR_LOCAL_NEW is not a 1074 | good candidate). 1075 | 1076 | lil_value_t lil_get_var(lil_t lil, 1077 | const char* name) 1078 | 1079 | which can be used to return the value of a variable. Alternatively 1080 | 1081 | lil_value_t lil_get_var_or(lil_t lil, 1082 | const char* name, 1083 | lil_value_t defvalue) 1084 | 1085 | which will return "defvalue" if the variable is not found. These two will 1086 | always use the "current" environment (which will be a local environment if 1087 | the function is called from a native function callback for a native 1088 | function called from a script function). 1089 | 1090 | lil_value_t lil_eval_expr(lil_t lil, 1091 | lil_value_t code) 1092 | 1093 | which can be used to evaluate an expression like the "expr" function. 1094 | 1095 | lil_value_t lil_unused_name(lil_t lil, 1096 | const char* part) 1097 | 1098 | which can be used to return an unused LIL name using the given part. 1099 | 1100 | Sometimes you need to associate some piece of data (like an object or a 1101 | script name) with a LIL runtime. You can use the following functions to 1102 | associate a pointer to a lil_t object and retrieve it: 1103 | 1104 | void lil_set_data(lil_t lil, 1105 | void* data) 1106 | 1107 | which associates "data" with the given lil object and 1108 | 1109 | void* lil_get_data(lil_t lil) 1110 | 1111 | which returns the associated data with the given lil object. By default 1112 | this will return NULL if no call to lil_set_data() is made. 1113 | 1114 | 4.7. LIL callback summary 1115 | -------------------- 1116 | Here is a summary of the LIL_CALLBACK_* constants for use with the 1117 | lil_callback() function: 1118 | 1119 | LIL_CALLBACK_EXIT 1120 | callback: lil_exit_callback_proc_t 1121 | signature: void (lil_t lil, lil_value_t arg) 1122 | called: when the LIL "exit" function is called 1123 | 1124 | LIL_CALLBACK_WRITE: 1125 | callback: lil_write_callback_proc_t 1126 | signature: void (lil_t lil, const char* msg) 1127 | called: when the "print" or "write" function is called. It is 1128 | expected to parse the newline character \n 1129 | 1130 | LIL_CALLBACK_READ: 1131 | callback: lil_read_callback_proc_t 1132 | signature: char* (lil_t lil, const char* name) 1133 | called: to read the file "name" and return its contents 1134 | 1135 | LIL_CALLBACK_SOURCE: 1136 | callback: lil_source_callback_proc_t 1137 | signature: char* (lil_t lil, const char* name) 1138 | called: to read the LIL source file "name" and return its code 1139 | 1140 | LIL_CALLBACK_STORE: 1141 | callback: lil_store_callback_proc_t 1142 | signature: void (lil_t lil, const char* name, const char* data) 1143 | called: to store "data" in the file "name" as its contents 1144 | 1145 | LIL_CALLBACK_ERROR: 1146 | callback: lil_error_callback_proc_t 1147 | signature: void (lil_t lil, size_t pos, const char* msg) 1148 | called: when an error occurs and is not handled 1149 | 1150 | LIL_CALLBACK_SETVAR: 1151 | callback: lil_setvar_callback_proc_t 1152 | signature: int (lil_t lil, const char* name, lil_value_t* value) 1153 | called: when a non-existant variable is assigned in the global 1154 | environment. If this returns a negative value, the 1155 | assignment does not occur. If this returns a zero, the 1156 | value originally to be written is assigned to the 1157 | variable. If this returns a positive value, the 1158 | value pointed by "value" is assigned. This can be used 1159 | to override or cancel the assignment of a variable 1160 | 1161 | LIL_CALLBACK_GETVAR: 1162 | callback: lil_getvar_callback_proc_t 1163 | signature: int (lil_t lil, const char* name, lil_value_t* value) 1164 | called: when a variable is to be read from the global environment. 1165 | If this function returns a non-zero value, the value 1166 | pointed to by "value" is used instead of the value that 1167 | would be normally returned. Otherwise the original value 1168 | is used 1169 | 1170 | 4.8. Using LIL as a DLL 1171 | ------------------ 1172 | The C code of LIL was not written to be used as a DLL, so keep that in 1173 | mind when you decide to use LIL via a DLL. Using LIL as a DLL requires a 1174 | couple of extra steps to be performed: 1175 | 1176 | * LIL itself and every code that includes lil.h must be compiled with 1177 | the LILDLL conditional defined. This will cause all public functions 1178 | to be marked as DLL exportable/importable and use the stdcall 1179 | calling convention. Note that because by default if no LILDLL is 1180 | defined the library will use the compiler's default calling 1181 | convention you shouldn't mix LILDLL with non-LILDLL sources 1182 | * The LILCALLBACK macro must be used for callbacks. For example this 1183 | 1184 | static lil_value_t fnc_hi(lil_t lil, 1185 | size_t argc, 1186 | lil_value_t* argv) 1187 | 1188 | must be changed to this 1189 | 1190 | static LILCALLBACK lil_value_t fnc_hi(lil_t lil, 1191 | size_t argc, 1192 | lil_value_t* argv) 1193 | 1194 | Under the "dll" directory there is an OpenWatcom project file which will 1195 | create a lil.dll file you can use. Note that it is highly recommended to 1196 | not mix different DLL versions. The LIL API and binary interface is not 1197 | frozen and the DLL interface might change. 1198 | 1199 | 1200 | 5. Integrating LIL in non-C programs 1201 | ------------------------------------ 1202 | It is possible to use LIL from non-C programs as long as a method to 1203 | link against C is provided and the language supports the data types used 1204 | by the public LIL interface (only data types are needed, the public 1205 | interface does not use C structs). Currently under Windows it is 1206 | recommended to use the DLL version of LIL built using the OpenWatcom 1207 | project found under the "dll" directory of the LIL repository (although it 1208 | might be possible to build a compatible version with MinGW or Visual C++, 1209 | i have not checked this). 1210 | 1211 | While you can write the interface yourself, there are some prewritten 1212 | interfaces which you can find at the Import LIL project at: 1213 | 1214 | https://github.com/badsector/implil 1215 | 1216 | Currently the following languages/environments are supported: 1217 | 1218 | * Visual C# / .NET 4 1219 | (will probably work under older versions, might work under Mono) 1220 | * FreePascal (and Lazarus) 1221 | 1222 | Check the above site for further and up-to-date information (might list 1223 | other supported interfaces). 1224 | 1225 | 1226 | 6. Contact 1227 | ---------- 1228 | Kostas Michalopoulos 1229 | badsector@runtimelegend.com 1230 | badsectoracula@gmail.com 1231 | 1232 | also see https://github.com/badsector/lil 1233 | 1234 | --------------------------------------------------------------------------------