@@ -6,14 +6,16 @@ import std/[
66 random,
77 os,
88 sequtils,
9- math
9+ math,
10+ enumerate
1011]
1112
1213from system/ nimscript import nil
1314
1415import
1516 npsenv,
1617 lexer,
18+ parser,
1719 builtinlibs/ [
1820 common,
1921 libstrings,
@@ -27,15 +29,28 @@ elif defined(danger):
2729else :
2830 const buildMode = " debug"
2931
30- const langVersion* = staticRead (" ../npscript.nimble" )
31- .split (" \n " )
32- .filterIt (it.startsWith (" version" ))[0 ]
33- .split (" =" )[^ 1 ]
34- .strip ()[1 ..^ 2 ] & (if buildMode != " release" : " +" & buildMode else : " " )
32+ const
33+ langVersion* = staticRead (" ../npscript.nimble" )
34+ .split (" \n " )
35+ .filterIt (it.startsWith (" version" ))[0 ]
36+ .split (" =" )[^ 1 ]
37+ .strip ()[1 ..^ 2 ] & (if buildMode != " release" : " +" & buildMode else : " " )
38+
39+ product = " NPScript"
40+
41+ helpMessage = staticRead (" data/helpmsg.txt" )
42+ .strip ()
43+ .colorize ()
44+
45+ helpMessageExtended = staticRead (" data/helpmsgext.txt" )
46+ .strip ()
47+ .colorize ()
48+
3549
3650static :
3751 echo " Compiling NPScript " , langVersion, " on " , nimscript.buildOS, " /" , nimscript.buildCPU, " for " , hostOS , " /" , hostCPU , " in " , buildMode, " mode"
3852
53+
3954let builtins* = newDict (0 )
4055
4156template addV (name, doc: static string , item: Value ) =
@@ -129,24 +144,47 @@ proc importFile*(s: State, path: string): Value =
129144 return substate.get (" export" )
130145
131146
147+ proc literalize (s: State , nodes: seq [Node ]): seq [Value ] =
148+ result = newSeq [Value ](nodes.len)
149+
150+ for (i, node) in enumerate (nodes):
151+ case node.typ
152+ of nSymbol:
153+ result [i] = newSymbol (node.tok.lit)
154+ of nString:
155+ result [i] = newString (node.tok.lit)
156+ of nInteger:
157+ let num = parseInt (node.tok.lit)
158+ result [i] = newInteger (num)
159+ of nReal:
160+ let num = parseFloat (node.tok.lit)
161+ result [i] = newReal (num)
162+ of nList:
163+ result [i] = newList (literalize (s, node.nodes))
164+ of nProc:
165+ result [i] = newProcedure (node.nodes)
166+ of nWord:
167+ result [i] = s.get (node.tok.lit)
168+
169+
132170# Meta operators
133171
134- addV (" langver " ,
172+ addV (" version " ,
135173"""
136- 'langver '
137- -> version
174+ 'version '
175+ -> string
138176Returns the current version of the language as a string.
139177""" ):
140178 newString (langVersion)
141179
142- const
143- helpMessage = staticRead ( " data/helpmsg.txt " )
144- . strip ()
145- . colorize ()
146-
147- helpMessageExtended = staticRead ( " data/helpmsgext.txt " )
148- . strip ()
149- . colorize ( )
180+ addV ( " product " ,
181+ """
182+ 'product'
183+ -> string
184+ Returns the product name.
185+ This is included for compatibility with other PostScript implementations.
186+ """ ):
187+ newString (product )
150188
151189# ->
152190# Prints a help message to assist people with writing the language.
@@ -205,7 +243,7 @@ The returned docstring may be empty.
205243# X -> typeof X
206244# Returns a symbol that describes the type of a value X.
207245addF (" type" , @ [(" X" , tAny)]):
208- let tstr = $ s.pop ().kind
246+ let tstr = $ s.pop ().typ
209247
210248 s.push (newSymbol (tstr))
211249
@@ -260,14 +298,24 @@ addF("quitn", @[("E", tInteger)]):
260298addF (" exit" , @ []):
261299 raise NpsExitError ()
262300
301+ # F -> F
302+ # Replaces operator names in F with operator values
303+ addF (" bind" , @ [(" F" , tProcedure)]):
304+ let f = s.pop ()
305+
306+ s.push (newProcedure (f, literalize (s, f.nodes)))
307+
263308# F ->
264309# Takes a function F and executes it.
265310addF (" exec" , @ [(" F" , tProcedure)]):
266311 let f = s.pop ()
267312
268313 s.check (f.args)
269-
270- f.run (sptr, r)
314+
315+ if f.ptype == ptLiteral:
316+ evalValues (s, r, f.values)
317+ else :
318+ f.run (sptr, r)
271319
272320# Stack operators
273321
@@ -347,7 +395,8 @@ addMathOp("mod", `%`)
347395# Computes the power of X and Y.
348396addMathOp (" exp" , `^`)
349397
350- addV (" pi" , """
398+ addV (" pi" ,
399+ """
351400-> pi
352401Returns the value of Pi.
353402""" ):
@@ -639,21 +688,27 @@ addF("array", @[("S", tInteger)]):
639688
640689# L I -> L[I]
641690# Gets the value at an index I of a list L.
691+ # Negative indexes will index from the back of the list
642692addF (" get" , @ [(" L" , tList), (" I" , tInteger)]):
643693 let
644- ind = s.pop ().intv
694+ i = s.pop ().intv
645695 arr = s.pop ()
646696
697+ let ind = if i < 0 : arr.len - - i else : i
698+
647699 s.push (arr[ind])
648700
649701# L I X -> L[I] = X
650702# Sets an index I of a list L to a value X.
703+ # Negative indexes will index from the back of the list
651704addF (" put" , @ [(" L" , tList), (" I" , tInteger), (" X" , tAny)]):
652705 let
653706 val = s.pop ()
654- ind = s.pop ().intv
707+ i = s.pop ().intv
655708 arr = s.pop ()
656709
710+ let ind = if i < 0 : arr.len - - i else : i
711+
657712 arr[ind] = val
658713
659714
@@ -694,6 +749,11 @@ addF("begin", @[("D", tDict)]):
694749addF (" end" , @ []):
695750 discard s.dend ()
696751
752+ # ->
753+ # Returns the last opened dictionary.
754+ addF (" this" , @ []):
755+ s.push (newDictionary (s.dicts[^ 1 ]))
756+
697757# D S ->
698758# Adds a symbol S from a dictionary D into the current dictionary.
699759# If S already exists in it current dictionary, it will be overwritten.
@@ -716,7 +776,6 @@ addF("allfrom", @[("D", tDict)]):
716776 for k, v in d.pairs:
717777 s.set (k, v)
718778
719-
720779addS (" scoped" ,
721780"""
722781'scoped'
@@ -742,12 +801,62 @@ begin
742801 if
743802end """
744803
745- # ->
746- # Shows the symbols inside the last opened dictionary.
804+ # -> L
805+ # Returns a list of the symbols inside the last opened dictionary.
747806addF (" symbols" , @ []):
748- for symbol in s.symbols ():
749- echo symbol
807+ let symbols = s.symbols
808+ var l = newSeq [ Value ](symbols.len)
750809
810+ for (i, symbol) in enumerate (symbols):
811+ l[i] = newSymbol (symbol)
812+
813+ s.push (newList (l))
814+
815+ # -> L
816+ # Returns a list of lists of the symbols in each dictionary.
817+ addF (" rsymbols" , @ []):
818+ let dicts = s.dicts
819+ var l = newSeq [Value ](dicts.len)
820+
821+ for (i, dict) in enumerate (dicts):
822+ var
823+ subl = newSeq [Value ](dict.len)
824+ j = 0
825+
826+ for symbol in dict.keys:
827+ subl[j] = newSymbol (symbol)
828+ inc j
829+
830+ l[i] = newList (subl)
831+
832+ s.push (newList (l))
833+
834+ addS (" psymbols" ,
835+ """
836+ 'psymbols'
837+ ->
838+ Shows the symbols inside the last opened dictionary.
839+ """ , @ []):
840+ " symbols {=} forall"
841+
842+ addS (" prsymbols" ,
843+ """
844+ 'prsymbols'
845+ ->
846+ # Shows the symbols in each dictionary.
847+ """ , @ []):
848+ """
849+ 1 rsymbols
850+ {
851+ exch dup
852+ (%f:\n) printf
853+ exch
854+
855+ {( ) printf =}
856+ forall
857+ 1 add
858+ } forall
859+ pop """
751860
752861# Misc operators
753862
@@ -756,22 +865,28 @@ let
756865 falseSingleton = newBool (false )
757866 nullSingleton = newNull ()
758867
759- addV (" null" , """
868+ addV (" null" ,
869+ """
760870'null'
761871-> null
762- Produces the value of null. """ ):
872+ Produces the value of null.
873+ """ ):
763874 nullSingleton
764875
765- addV (" true" , """
876+ addV (" true" ,
877+ """
766878'true'
767879-> true
768- Produces the boolean true value. """ ):
880+ Produces the boolean true value.
881+ """ ):
769882 trueSingleton
770883
771- addV (" false" , """
884+ addV (" false" ,
885+ """
772886'false'
773887-> false
774- Produces the boolean false value. """ ):
888+ Produces the boolean false value.
889+ """ ):
775890 falseSingleton
776891
777892# X -> len of X
0 commit comments