19 Commitit

Tekijä SHA1 Viesti Päivämäärä
  MaximeBarniaudy b142d94b11 Delare Stream object in C code and add primitive for stream string matching. Also refactor the rollback mechanism in the grammar parser to give responsibility to the right object. 11 kuukautta sitten
  MaximeBarniaudy 1e73ce0d16 Make grammar_parser.meta use the entire grammar from minproto.leg 11 kuukautta sitten
  MaximeBarniaudy 0a6802237f Add optional base argument to String.asInteger 11 kuukautta sitten
  MaximeBarniaudy e482c081a9 Fix error after single quote semantics change 1 vuosi sitten
  MaximeBarniaudy 45686c7730 Add with and without functions for namespace manimulation, add namespace support to grammars, add test of parser circularity 1 vuosi sitten
  MaximeBarniaudy 23be24b142 parser circularity 1 vuosi sitten
  MaximeBarniaudy 4b1752f399 dotdot got lost in merging 1 vuosi sitten
  MaximeBarniaudy 35fa3e9158 Add Invoke and GetProp 1 vuosi sitten
  MaximeBarniaudy be4e0b8322 Minimal grammar parsing 1 vuosi sitten
  MaximeBarniaudy 7b914a509c Add an intern primitive for symbol creation 1 vuosi sitten
  MaximeBarniaudy 6de35d8a4a Fix range access overshadowing key access 1 vuosi sitten
  WitherFlower dbc8265409 Merge range access and grammar parser changes 1 vuosi sitten
  Ian Piumarta 2171f47dce Fold constants during parsing if FOLDCONST=1. 11 kuukautta sitten
  Ian Piumarta 4d396d6170 Fix floating point comparison and assignment operators. 11 kuukautta sitten
  Ian Piumarta 883a9cf7c2 Remove let and ::. Add global keyword. Add Ref/Get/SetSym. Cast the 0 terminator in genericError to oop to ensure va_arg picks it up. Better error messages for broken statements in blocks and broken expressions in argument lists. 11 kuukautta sitten
  Ian Piumarta ea60878c24 Add exception tests. New test.txt reference output. 11 kuukautta sitten
  Ian Piumarta dcbef49750 Exceptions are supported with syntax "try {} catch (e) {}", "try {} ensure {}", and "raise e". Add catch to the list of words that can end an expression statement. Most runtime errors are reported using exceptions when EXCEPTIONS=1. Add String_repeat() supporting multiplying a string and an integer. Illegal escape sequence in a string is a warning not an error. Break and continue work properly in while(). ForFromTo evaluates its start and end arguments. Rename primitive fatal() to error(). 11 kuukautta sitten
  Ian Piumarta 207ef22fb0 Upate test reference output. 11 kuukautta sitten
  Ian Piumarta 46c7ef6f32 Run the first non-option command line argument as the program. Set _argv__ to program name plus any following command-line arguments. 11 kuukautta sitten
7 muutettua tiedostoa jossa 2397 lisäystä ja 260 poistoa
  1. +1079
    -0
      grammar_parser.meta
  2. +805
    -244
      minproto.leg
  3. +73
    -0
      rawMetaGrammar.leg
  4. +78
    -0
      rawgrammar.leg
  5. +255
    -0
      rawminproto.leg
  6. +61
    -14
      test.ref
  7. +46
    -2
      test.txt

+ 1079
- 0
grammar_parser.meta
File diff suppressed because it is too large
Näytä tiedosto


+ 805
- 244
minproto.leg
File diff suppressed because it is too large
Näytä tiedosto


+ 73
- 0
rawMetaGrammar.leg Näytä tiedosto

@ -0,0 +1,73 @@
statement = b:block { b; }
| e:expression SEMI { e; }
expression = p:primary
( DOT i:id ASSIGN e:expression # { $$ = newSetProp(p, i, e) }
| LBRAK i:expression RBRAK ASSIGN e:expression { SetArray.new(object: p, index: i, value: e); }
)
| i:id ASSIGN e:expression { SetVar.new(name: i, value: e); }
| pf:postfix { pf; }
postfix = p:primary
( DOT i:id a:args !ASSIGN !LBRACE { p = Invoke.new(self: p, method: i, arguments: a); }
| DOT i:id !ASSIGN { p = GetProp.new(object: p, key: i); }
| a:args !ASSIGN !LBRACE { p = Call.new(function: p, arguments: a); }
) * { p; }
args = LPAREN a:mklist
(
( k:id COLON e:expression { a[k] = e; }
| e:expression { a.push(e); }
)
( COMMA
( k:id COLON e:expression { a[k] = e; }
| e:expression { a.push(e); }
)
) *
) ? RPAREN { a; }
mklist = { Object.new(); }
primary = nil | number | var | subExpr
subExpr = LPAREN e:expression RPAREN { e; }
block = LBRACE b:mklist
( e:statement { b.push(e); }
) * RBRACE { Block.new(body: b); }
nil = NIL { nil; }
number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) }
| "+" n:number { n }
| n:unsign { n }
unsign = < DIGIT+ > - { yytext.asInteger(10); }
var = i:id { GetVar.new(name: i); }
id = < LETTER ALNUM* > - { intern(yytext); }
DIGIT = [0-9]
LETTER = [A-Za-z_]
ALNUM = LETTER | DIGIT
NIL = "nil" !ALNUM -
SEMI = ";" -
COMMA = "," -
LPAREN = "(" -
RPAREN = ")" -
LBRAK = "[" -
RBRAK = "]" -
LBRACE = "{" -
RBRACE = "}" -
COLON = ":" ![:] -
ASSIGN = "=" ![=] -
DOT = "." ![.] -
- = ( space | comment )*
space = ' ' | '\t' | end-of-line
comment = '//' ( !end-of-line . )* end-of-line
end-of-line = '\r\n' | '\n' | '\r'
end-of-file = !.

+ 78
- 0
rawgrammar.leg Näytä tiedosto

@ -0,0 +1,78 @@
grammar = -
( d:definition { set(d.name, d.expression); }
) + end-of-file
definition = i:identifier ASSIGN e:expression SEMI? { Definition.new(name: i, expression: e); }
expression = s:sequence !BAR { s; }
| s1:sequence { s1 = Alternation.new().push(s1); }
( BAR s2:sequence { s1.push(s2); }
) * { s1; }
sequence = p:prefix { p = Sequence.new().push(p); }
( q:prefix { p.push(q); }
) * { p; }
prefix = AND a:action { ParseTimeAction.new(action: a); }
|
( AND s:suffix { And.new(expression: s); }
| NOT s:suffix { Not.new(expression: s); }
| s:suffix { s; }
)
suffix = p:primary
( QUERY { p = Optional.new(expression: p); }
| STAR { p = Star.new(expression: p); }
| PLUS { p = Plus.new(expression: p); }
) ? { p; }
primary = i1:identifier COLON i2:ruleCall !ASSIGN { Assignment.new(name: i1, rule: i2); }
| i:ruleCall !ASSIGN { i; }
| LPAREN e:expression RPAREN { e; }
| l:literal { l; }
| c:class { c; }
| DOT { Dot.new(); }
| a:action { a; }
| BEGIN { Begin.new(); }
| END { End.new(); }
identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { intern(yytext); }
ruleCall = n:identifier CCOLON r:identifier { NamespacedRuleCall.new(namespace: n, name: r); }
| i:identifier { RuleCall.new(name: i); }
literal = ['] < ( !['] char )* > ['] - { StringLiteral.new(string: yytext); }
| ["] < ( !["] char )* > ["] - { StringLiteral.new(string: yytext); }
class = '[' < ( !']' range )* > ']' - { CharacterClass.new(value: yytext); }
range = char '-' char | char
char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [0-7][0-7]?
| !'\\' .
action = m:metaLanguage::block - { Action.new(parseTree: m); }
- = ( space | comment )*
space = ' ' | '\t' | end-of-line
comment = '#' ( !end-of-line . )* end-of-line
end-of-line = '\r\n' | '\n' | '\r'
end-of-file = !.
BAR = '|' -
NOT = '!' -
QUERY = '?' -
BEGIN = '<' -
END = '>' -
SEMI = ";" -
CCOLON = "::" -
LPAREN = "(" -
RPAREN = ")" -
ASSIGN = "=" ![=] -
AND = "&" ![&=] -
PLUS = "+" ![+=] -
STAR = "*" ![=] -
DOT = "." ![.] -
COLON = ":" ![:] -

+ 255
- 0
rawminproto.leg Näytä tiedosto

@ -0,0 +1,255 @@
start = - ( s:stmt # { yysval = s }
| !. # { yysval = 0 }
| < (!EOL .)* > # { fatal("syntax error near: %s", yytext) }
)
stmt = LET l:mklet k:id ASSIGN v:expr { l.keyvals.push(k); l.keyvals.push(v) }
( COMMA k:id ASSIGN v:expr { l.keyvals.push(k); l.keyvals.push(v) }
)* SEMI { l }
| WHILE LPAREN c:expr RPAREN s:stmt { While.new(condition: c, body: s) }
| IF LPAREN c:expr RPAREN s:stmt
( ELSE t:stmt { If.new(condition: c, consequent: s, alternate: t ) }
| { If.new(condition: c, consequent: s, alternate: nil) }
)
| CONT EOS { Continue.new() }
| BREAK e:expr EOS { Break.new(value: e) }
| BREAK EOS { Break.new(value: nil) }
| RETURN e:expr EOS { Return.new(value: e) }
| RETURN EOS { Return.new(value: nil) }
| FOR LPAREN i:id IN e:expr RPAREN
s:stmt { ForIn.new(identifier: i, expression: e, body: s) }
| FOR LPAREN i:id FROM a:expr
TO b:expr RPAREN s:stmt { ForFromTo.new(identifier: i, first: a, last: b, body: s) }
| FOR LPAREN i:expr SEMI c:expr SEMI
u:expr RPAREN s:stmt { For.new(initialise: i, condition: c, update: u, body: s) }
| i:id p:params b:block { SetVar.new(name: i, value: Lambda.new(parameters: p, body: b)) }
| v:proto DOT i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) }
| v:proto CCOLON i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) }
| b:block { Block.new(body: b) }
| e:expr EOS { e }
mklet = { Let.new() }
proto = v:var ( DOT j:id !LPAREN { v = GetProp.new(object: v, key: j) }
)* { v }
EOS = SEMI+ | &RBRACE | &ELSE
expr = i:id ASSIGN e:expr { SetVar.new(name: i, value: e) }
| l:logor ( ASSIGN r:expr { l = assign(l, r) }
| PLUSEQ r:expr { l = newBinop(__opPreAdd, lvalue(l), r) }
| MINUSEQ r:expr { l = newBinop(__opPreSub, lvalue(l), r) }
| STAREQ r:expr { l = newBinop(__opPreMul, lvalue(l), r) }
| SLASHEQ r:expr { l = newBinop(__opPreDiv, lvalue(l), r) }
| PCENTEQ r:expr { l = newBinop(__opPreMod, lvalue(l), r) }
| SHLEQ r:expr { l = newBinop(__opPreShl, lvalue(l), r) }
| SHREQ r:expr { l = newBinop(__opPreShr, lvalue(l), r) }
| ANDEQ r:expr { l = newBinop(__opPreAnd, lvalue(l), r) }
| XOREQ r:expr { l = newBinop(__opPreXor, lvalue(l), r) }
| OREQ r:expr { l = newBinop(__opPreOr, lvalue(l), r) }
)? { l }
logor = l:logand ( BARBAR r:logand { l = newBinop(__opLogOr, l, r) }
)* { l }
logand = l:bitor ( ANDAND r:bitor { l = newBinop(__opLogAnd, l, r) }
)* { l }
bitor = l:bitxor ( OR r:bitxor { l = newBinop(__opBitOr, l, r) }
)* { l }
bitxor = l:bitand ( XOR r:bitand { l = newBinop(__opBitXor, l, r) }
)* { l }
bitand = l:eq ( AND r:eq { l = newBinop(__opBitAnd, l, r) }
)* { l }
eq = l:ineq ( EQ r:ineq { l = newBinop(__opEq, l, r) }
| NOTEQ r:ineq { l = newBinop(__opNotEq, l, r) }
)* { l }
ineq = l:shift ( LESS r:shift { l = newBinop(__opLess, l, r) }
| LESSEQ r:shift { l = newBinop(__opLessEq, l, r) }
| GRTREQ r:shift { l = newBinop(__opGrtrEq, l, r) }
| GRTR r:shift { l = newBinop(__opGrtr, l, r) }
)* { l }
shift = l:sum ( SHL r:sum { l = newBinop(__opShl, l, r) }
| SHR r:sum { l = newBinop(__opShr, l, r) }
)* { l }
sum = l:prod ( PLUS r:prod { l = newBinop(__opAdd, l, r) }
| MINUS r:prod { l = newBinop(__opSub, l, r) }
)* { l }
prod = l:range ( STAR r:range { l = newBinop(__opMul, l, r) }
| SLASH r:range { l = newBinop(__opDiv, l, r) }
| PCENT r:range { l = newBinop(__opMod, l, r) }
) * { l }
range = i1:prefix ( DOTDOT i2:prefix { i1 = Range.new(start: i1, end: i2) }
) ? { i1 }
prefix = PPLUS p:prefix { newBinop(__opPreAdd, lvalue(p), 1) }
| MMINUS p:prefix { newBinop(__opPreSub, lvalue(p), 1) }
| PLING p:prefix { Unyop.new(operation: __opNot).push(p) }
| MINUS p:prefix { Unyop.new(operation: __opNeg).push(p) }
| TILDE p:prefix { Unyop.new(operation: __opCom).push(p) }
| BQUOTE s:stmt { Unyop.new(operation: __opQuasiquote).push(s) }
| COMMAT e:expr { Unyop.new(operation: __opUnquote).push(e) }
| postfix
postfix = p:primary
( LBRAK e:expr RBRAK { p = GetArray.new(object: p, index: e) }
| DOT i:id ( a:args !LBRACE { p = Invoke.new(self: p, method: i, arguments: a) }
| { p = GetProp.new(object: p, key: i) }
)
| a:args !LBRACE { p = newApply(p, a) }
| CCOLON i:id { p = GetProp.new(object: p, key: i) }
)*
( PPLUS { p = newBinop(__opPostAdd, lvalue(p), 1) }
| MMINUS { p = newBinop(__opPostAdd, lvalue(p), -1) }
)? { p }
args = LPAREN a:mkobj
( RPAREN
| ( k:id COLON e:expr { a[k] = e }
| e:expr { a.push(e) }
)
( COMMA ( k:id COLON e:expr { a[k] = e }
| e:expr { a.push(e) }
) )* RPAREN ) { a }
params = LPAREN p:mkobj
( RPAREN
| i:id ( COLON e:expr { p[i] = e }
| { p.push(i) }
)
( COMMA i:id ( COLON e:expr { p[i] = e }
| { p.push(i) }
)
)* RPAREN ) { p }
mkobj = { Object.new() }
primary = nil | number | string | symbol | var | lambda | subexpr | literal
lambda = p:params b:block { Lambda.new(parameters: p, body: b) }
subexpr = LPAREN e:expr RPAREN { e }
| b:block { Block.new(body: b) }
literal = LBRAK o:mkobj
( RBRAK
| ( ( i:id COLON e:expr { o[i] = e }
| e:expr { o.push(e) }
) ( COMMA ( i:id COLON e:expr { o[i] = e }
| e:expr { o.push(e) }
) )* )? RBRAK ) { Literal.new(object: o) }
block = LBRACE b:mkobj
( e:stmt { b.push(e) }
)* RBRACE { Block.new(body: b) }
nil = NIL { nil }
number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) }
| "+" n:number { n }
| n:unsign { n }
unsign = < DIGIT* '.' DIGIT+ EXP? > - { yytext.asFloat() }
| "0" [bB] < BIGIT+ > - { yytext.asInteger(2) }
| "0" [xX] < HIGIT+ > - { yytext.asInteger(16) }
| "0" < OIGIT* > - { yytext.asInteger(8) }
| < DIGIT+ > - { yytext.asInteger() }
string = '"' < ( !'"' char )* > '"' - { yytext.unescaped() }
| "'" < ( !"'" char )* > "'" - { yytext.unescaped() }
char = "\\" ( ["'\\abfnrtv]
| [xX] HIGIT*
| [0-7][0-7]?[0-7]?
)
| .
symbol = HASH i:id { i }
var = i:id { GetVar.new(name: i) }
id = < LETTER ALNUM* > - { intern(yytext) }
BIGIT = [0-1]
OIGIT = [0-7]
DIGIT = [0-9]
HIGIT = [0-9A-Fa-f]
LETTER = [A-Za-z_]
ALNUM = LETTER | DIGIT
SIGN = [-+]
EXP = [eE] SIGN DIGIT+
- = SPACE*
SPACE = [ \t] | EOL | '//' (!EOL .)*
EOL = [\n\r] # { ++lineno }
NIL = "nil" !ALNUM -
WHILE = "while" !ALNUM -
IF = "if" !ALNUM -
ELSE = "else" !ALNUM -
FOR = "for" !ALNUM -
IN = "in" !ALNUM -
FROM = "from" !ALNUM -
TO = "to" !ALNUM -
LET = "let" !ALNUM -
CONT = "continue" !ALNUM -
BREAK = "break" !ALNUM -
RETURN = "return" !ALNUM -
BQUOTE = "`" -
COMMAT = "@" -
HASH = "#" -
SEMI = ";" -
ASSIGN = "=" ![=] -
COMMA = "," -
COLON = ":" ![:] -
CCOLON = "::" -
LPAREN = "(" -
RPAREN = ")" -
LBRAK = "[" -
RBRAK = "]" -
LBRACE = "{" -
RBRACE = "}" -
BARBAR = "||" ![=] -
ANDAND = "&&" ![=] -
OR = "|" ![|=] -
OREQ = "|=" -
XOR = "^" ![=] -
XOREQ = "^=" -
AND = "&" ![&=] -
ANDEQ = "&=" -
EQ = "==" -
NOTEQ = "!=" -
LESS = "<" ![<=] -
LESSEQ = "<=" -
GRTREQ = ">=" -
GRTR = ">" ![=] -
SHL = "<<" ![=] -
SHLEQ = "<<=" -
SHR = ">>" ![=] -
SHREQ = ">>=" -
PLUS = "+" ![+=] -
PLUSEQ = "+=" -
PPLUS = "++" -
MINUS = "-" ![-=] -
MINUSEQ = "-=" -
MMINUS = "--" -
STAR = "*" ![=] -
STAREQ = "*=" -
SLASH = "/" ![/=] -
SLASHEQ = "/=" -
PCENT = "%" ![=] -
PCENTEQ = "%=" -
DOT = "." ![.] -
DOTDOT = ".." -
PLING = "!" ![=] -
TILDE = "~" -

+ 61
- 14
test.ref Näytä tiedosto

@ -54,11 +54,14 @@ Point.new(x:3, y:4).magnitude() => 5.000000
| __eval__: <primitive Object.__eval__> | __eval__: <primitive Object.__eval__>
| __name__: Object | __name__: Object
| allKeys: <primitive Object.allKeys> | allKeys: <primitive Object.allKeys>
| findKey: <primitive Object.findKey>
| includes: <primitive Object.includes>
| keys: <primitive Object.keys> | keys: <primitive Object.keys>
| length: <primitive Object.length> | length: <primitive Object.length>
| new: <primitive Object.new> | new: <primitive Object.new>
| pop: <primitive Object.pop> | pop: <primitive Object.pop>
| push: <primitive Object.push> | push: <primitive Object.push>
| reversed: <primitive Object.reversed>
| sorted: <primitive Object.sorted> | sorted: <primitive Object.sorted>
nil no nil no
1 yes 1 yes
@ -152,6 +155,49 @@ f 102 ( 40 ) 41 32 { 123 32 p 112 r 114 i 105 n 110 t 116 ( 40 _ 95 _ 95 e 1
42 42
6 * 7 6 * 7
MACRO table <<Object>> MACRO table <<Object>>
| assert: <<Closure>>
| | environment: nil
| | function: <<Lambda>>
| | | body: <<Object>>
| | | | 0: <<Unyop>>
| | | | | operation: 3
| | | | | 0: <<Block>>
| | | | | | body: <<Object>>
| | | | | | | 0: <<If>>
| | | | | | | | alternate: nil
| | | | | | | | condition: <<Unyop>>
| | | | | | | | | operation: 0
| | | | | | | | | 0: <<Call>>
| | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | 0: <<Unyop>>
| | | | | | | | | | | | operation: 4
| | | | | | | | | | | | 0: <<GetVar>>
| | | | | | | | | | | | | name: x
| | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | name: eval
| | | | | | | | consequent: <<Block>>
| | | | | | | | | body: <<Object>>
| | | | | | | | | | 0: <<Call>>
| | | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | | 0: "\nassertion failed: "
| | | | | | | | | | | | 1: <<Unyop>>
| | | | | | | | | | | | | operation: 4
| | | | | | | | | | | | | 0: <<Call>>
| | | | | | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | | | | | 0: <<GetVar>>
| | | | | | | | | | | | | | | | name: x
| | | | | | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | | | | | name: codeString
| | | | | | | | | | | | 2: "\n"
| | | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | | name: print
| | | | | | | | | | 1: <<Call>>
| | | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | | 0: 1
| | | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | | name: exit
| | | parameters: <<Object>>
| | | | 0: x
| test: <<Closure>> | test: <<Closure>>
| | environment: nil | | environment: nil
| | function: <<Lambda>> | | function: <<Lambda>>
@ -201,17 +247,18 @@ AST eval => 42
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
65 66 67 68 69 65 66 67 68 69
1 two 3 four 1 two 3 four
test.txt:381: *: illegal operand types Integer and String
11: n * factorial(n - 1)
10: if (n < 2) "1" else n * factorial(n - 1)
9: factorial(n - 1)
8: n * factorial(n - 1)
7: if (n < 2) "1" else n * factorial(n - 1)
6: factorial(n - 1)
5: n * factorial(n - 1)
4: if (n < 2) "1" else n * factorial(n - 1)
3: factorial(n - 1)
2: n * factorial(n - 1)
1: if (n < 2) "1" else n * factorial(n - 1)
0: factorial(5)
*: type error: illegal operand types: <Integer> and <Undefined>
13: n * factorial(n - 1)
12: if (n < 2) nil else n * factorial(n - 1)
11: factorial(n - 1)
10: n * factorial(n - 1)
9: if (n < 2) nil else n * factorial(n - 1)
8: factorial(n - 1)
7: n * factorial(n - 1)
6: if (n < 2) nil else n * factorial(n - 1)
5: factorial(n - 1)
4: n * factorial(n - 1)
3: if (n < 2) nil else n * factorial(n - 1)
2: factorial(5)
1: { factorial(5) }
0: try { factorial(5) } catch (e) { { if (!eval(e.__function__ == "*")) { print("\nassertion failed: ", "e.__function__ == \"*\"", "\n"); exit(1) } }; { if (!eval(e.__kind__ == "type error")) { print("\nassertion failed: ", "e.__kind__ == \"type error\"", "\n"); exit(1) } }; { if (!eval(e.__message__ == "illegal operand types")) { print("\nassertion failed: ", "e.__message__ == \"illegal operand types\"", "\n"); exit(1) } }; { if (!eval(e.operand1 == 2)) { print("\nassertion failed: ", "e.operand1 == 2", "\n"); exit(1) } }; { if (!eval(e.operand2 == nil)) { print("\nassertion failed: ", "e.operand2 == nil", "\n"); exit(1) } }; print(e.__function__, ": ", e.__kind__, ": ", e.__message__, ": ", typeName(e.operand1), " and ", typeName(e.operand2), "\n"); let w = 2; let j = i; while (j /= 10 >= 0) { w += 1 }; for (i from len(e) - 1 to 0) print(pad(w, codeString(i)), ": ", codeString(e[i]), "\n") }

+ 46
- 2
test.txt Näytä tiedosto

@ -92,6 +92,7 @@ nfib(n) { if (n < 2) 1 else nfib(n-1) + nfib(n-2) + 1 }
print(nfib(5), "\n"); print(nfib(5), "\n");
print(nfib(15), "\n"); print(nfib(15), "\n");
/*
assert(x) { assert(x) {
if (!(eval(x))) { if (!(eval(x))) {
print("\nassertion failed: ", codeString(x), "\n"); print("\nassertion failed: ", codeString(x), "\n");
@ -100,6 +101,14 @@ assert(x) {
} }
assert.fixed = #t; // do not evaluate arguments (x will be an AST suitable for eval()) assert.fixed = #t; // do not evaluate arguments (x will be an AST suitable for eval())
*/
Symbol.macros.assert = (x) {
`{if (!(eval(@x))) {
print("\nassertion failed: ", @codeString(x), "\n");
exit(1);
}};
};
refute(x) { refute(x) {
if (eval(x)) { if (eval(x)) {
@ -369,12 +378,47 @@ ast = (`6 * @myNode;); // user-defined node in AST
print("AST eval => ", eval(ast), "\n"); print("AST eval => ", eval(ast), "\n");
print("String to int conversion\n");
print("11111111".asInteger(2), "\n");
print("377".asInteger(8), "\n");
print("255".asInteger(), "\n");
print("FF".asInteger(16), "\n");
for (i from 0 to 10) print(i, " "); print("\n"); for (i from 0 to 10) print(i, " "); print("\n");
for (i from 10 to 0) print(i, " "); print("\n"); for (i from 10 to 0) print(i, " "); print("\n");
for (i in 10) print(i, " "); print("\n"); for (i in 10) print(i, " "); print("\n");
for (i in "ABCDE") print(i, " "); print("\n"); for (i in "ABCDE") print(i, " "); print("\n");
for (i in [1, "two", 3, "four"]) print(i, " "); print("\n"); for (i in [1, "two", 3, "four"]) print(i, " "); print("\n");
factorial(n) { if (n < 2) "1" else n * factorial(n-1) }
factorial(n) { if (n < 2) nil else n * factorial(n-1) }
typeName(x) {
if (!x) return "<Undefined>";
let name = "?";
let level = 1;
while (x && !x.allKeys().includes(#__name__)) x = x.__delegate__;
if (x.allKeys().includes(#__name__)) name = x.__name__.asString();
"<" * level + name + ">" * level;
}
factorial(5);
pad(w, i) {
while (len(i) < w) i = " " + i;
i;
}
try {
factorial(5);
}
catch (e) {
assert(e.__function__ == "*");
assert(e.__kind__ == "type error");
assert(e.__message__ == "illegal operand types");
assert(e.operand1 == 2);
assert(e.operand2 == nil);
print(e.__function__, ": ", e.__kind__, ": ", e.__message__, ": ", typeName(e.operand1), " and ", typeName(e.operand2), "\n");
let w = 2;
let j = i;
while ( (j /= 10) > 0) { ++w; }
for (i from len(e) - 1 to 0)
print(pad(w, codeString(i)), ": ", codeString(e[i]), "\n");
}

Ladataan…
Peruuta
Tallenna