10 Revīzijas

Autors SHA1 Ziņojums Datums
  MaximeBarniaudy 9e62769e4f dotdot got lost in merging pirms 1 gada
  MaximeBarniaudy 2daa814bcd Add Invoke and GetProp pirms 1 gada
  MaximeBarniaudy 929b5c098a Minimal grammar parsing pirms 1 gada
  MaximeBarniaudy f956a50a4c Add an intern primitive for symbol creation pirms 1 gada
  MaximeBarniaudy c110c4cc5d Fix range access overshadowing key access pirms 1 gada
  WitherFlower d47dfe2127 Merge range access and grammar parser changes pirms 1 gada
  Ian Piumarta 2761c99ce2 Object.dump() uses Object.allKeys() instead of Object.keys(). pirms 1 gada
  Ian Piumarta 31e6d2ff3d Primitives have correct names. Primitive Object.keys() returns properties that do not begin with "__". Add method Object.allKeys() that returns properties that do not begin with "__". Add method Object.sorted() to sort indexable elements. Add function sorted() for String and Object. Relations do not consider strings and symbols to be comparable. Printing strings does not include quotation marks at indentation levels 0 and 1. Printing strings escapes control characters at indentation levels other than 0 and 1. Rename SetVar.expr to SetVar.value to be consistent with SetProp and SetArray. Add RefVar, RefProp, RefArray that compute address of assignable value. Add Binops for autoincrement and assignment operators. Any expression can be the subject of increment or assignment operator. Enforce lvalue for increment and assignment operators by semanic check, not in syntax. String literals can contain escaped quotation marks. Keyword:value pairs in parameter lists provide arbitray expressions as default parameter values. Evaluate and assign default parameters values in apply(). pirms 1 gada
  Ian Piumarta ff3dda9f83 Include recent results as comments. pirms 1 gada
  Ian Piumarta 956adf81e4 Define _GNU_SOURCE to expose qsort_r(). pirms 1 gada
7 mainītis faili ar 1392 papildinājumiem un 223 dzēšanām
Dalītais skats
  1. +1
    -1
      Makefile
  2. +6
    -2
      bench-sieve.txt
  3. +3
    -0
      bench.txt
  4. +924
    -0
      grammar_parser.meta
  5. +431
    -204
      minproto.leg
  6. +23
    -14
      test.ref
  7. +4
    -2
      test.txt

+ 1
- 1
Makefile Parādīt failu

@ -1,7 +1,7 @@
OFLAGS += -Wall -Wno-unused -O3 -DNDEBUG
GFLAGS += -Wall -Wno-unused -g
PFLAGS += $(OFLAGS) -pg
CFLAGS += -I/opt/local/include
CFLAGS += -D_GNU_SOURCE -I/opt/local/include
LDLIBS += -L/opt/local/lib
LDLIBS += -lgc -lm

+ 6
- 2
bench-sieve.txt Parādīt failu

@ -1,5 +1,9 @@
numbers = 8192; // 1028 primes
repeats = 50;
// M1 TYPECODES+DELOPT
// 178589010 nodes evaluated in 2.129754 seconds = 83854290 nodes/sec
// 178589010 nodes evaluated in 2.126711 seconds = 83974273 nodes/sec
numbers = 819200; // 1028 primes
repeats = 10;
count = 0;

+ 3
- 0
bench.txt Parādīt failu

@ -1,3 +1,6 @@
// M1 TYPECODES+DELOPT
// 7049155 calls in 1.951509 seconds = 3612156 calls/sec -- pre binop functions
nfib = (n) { if (n < 2) 1; else nfib(n-1) + nfib(n-2) + 1; };
then = cputime();

+ 924
- 0
grammar_parser.meta Parādīt failu

@ -0,0 +1,924 @@
// Utils
println = (x) {
if (!x) {
print("\n");
} else {
print(x, "\n", full: 1);
}
};
Object.subtype(name) { self.new(__name__: name) }
// Input stream
Stream = Object.subtype(#Stream);
newStream(string) {
let self = Stream.new(
content: string,
position: 0,
limit: len(string)
);
print("Created new stream object: { position: ", self.position, ", limit: ", self.limit, ", !atEnd(): ", !self.atEnd(), " }\n");
self;
}
Stream.atEnd() { self.position >= self.limit }
Stream.peek() { !self.atEnd() && self.content[self.position] }
Stream.inc() { !self.atEnd() && { self.position = self.position + 1; } }
Stream.next() {
!self.atEnd() && {
let c = self.content[self.position];
self.position = self.position + 1;
c;
}
}
Stream.setLastBegin = () { self.lastBegin = self.position; };
// Context
Context = Object.subtype(#Context);
Context.init() { self.variables = []; self; }
Context.declareVariable(var) {
let found = 0;
for (key in self.variables.keys()) {
if (key == var) {
found = 1;
}
}
if (found == 0) {
self.variables[var] = nil;
}
}
// ----- Grammar Constructs -----
// String Literal
StringLiteral = Object.subtype(#StringLiteral);
StringLiteral.match(stream, context, rules, actions) {
let n = len(self.string);
let i = 0;
let success = 1;
if (stream.atEnd()) { success = 0; }
startPosition = stream.position;
while(i < n && success == 1) {
if (self.string[i] != stream.peek()) {
success = 0;
stream.position = startPosition;
} else {
i = i + 1;
stream.inc();
}
}
success;
}
// Character Class
CharacterClass = Object.subtype(#CharacterClass);
CharacterClass.match(stream, context, rules, actions) {
let classLength = len(self.value);
let i = 0;
let prevChar = nil;
let success = 0;
while (i < classLength && success == 0 && !stream.atEnd()) {
// [a] case
if (prevChar == nil) {
// println("[a] case");
prevChar = self.value[i];
if (stream.peek() == self.value[i]) {
success = 1;
}
} else if (prevChar != nil && self.value[i] == ord('-')) {
// [a-z] case
if (i+1 < classLength) {
// println("[a-z] case");
rangeStart = prevChar;
rangeEnd = self.value[i+1];
// print("Range Start: ", rangeStart, " | ");
// print("Range End: ", rangeEnd, "\n");
if (stream.peek() >= rangeStart
&& stream.peek() <= rangeEnd
) {
success = 1;
}
prevChar = nil;
i = i + 1;
// [a-] case
} else {
// println("[a-] case");
if (stream.peek() == ord('-')) {
success = 1;
}
}
// [ab] case
} else if (prevChar != nil && self.value[i] != ord('-')) {
// println("[ab] case");
prevChar = self.value[i];
if (stream.peek() == self.value[i]) {
success = 1;
}
}
// print("prevChar: ", prevChar, "\n");
i = i + 1;
}
if (success == 1) {
stream.inc();
}
success;
}
// Dot
Dot = Object.subtype(#Dot);
Dot.match(stream, context, rules, actions) {
if (!stream.atEnd()) {
stream.inc();
1;
} else {
0;
}
}
// Begin
Begin = Object.subtype(#Begin);
Begin.match(stream, context, rules, actions) {
stream.setLastBegin();
1;
}
// End
End = Object.subtype(#End);
End.match(stream, context, rules, actions) {
context.variables.yytext = stream.content[stream.lastBegin..stream.position];
1;
}
// Optional (? postfix operator)
Optional = Object.subtype(#Optional);
Optional.match(stream, context, rules, actions) {
let initialActionCount = actions.length();
let startingPosition = stream.position;
let success = self.expression.match(stream, context, rules, actions);
if (success == 0) {
while (actions.length() > initialActionCount) {
actions.pop();
}
stream.position = startingPosition;
}
1;
}
// Star
Star = Object.subtype(#Star);
Star.match(stream, context, rules, actions) {
while (self.expression.match(stream, context, rules, actions) == 1) {}
1;
}
// Plus
Plus = Object.subtype(#Plus);
Plus.match(stream, context, rules, actions) {
if (self.expression.match(stream, context, rules, actions) == 1) {
while (self.expression.match(stream, context, rules, actions) == 1) {}
1;
} else {
0;
}
}
// And
And = Object.subtype(#And);
And.match(stream, context, rules, actions) {
let position = stream.position;
if (self.expression.match(stream, context, rules, actions) == 1) {
stream.position = position;
1;
} else {
0;
}
}
// Not
Not = Object.subtype(#Not);
Not.match(stream, context, rules, actions) {
let position = stream.position;
if (self.expression.match(stream, context, rules, actions) == 1) {
stream.position = position;
0;
} else {
1;
}
}
// Sequence
Sequence = Object.subtype(#Sequence);
Sequence.match(stream, context, rules, actions) {
let i = 0;
let match = 1;
while (i < self.length() && match == 1) {
match = self[i].match(stream, context, rules, actions);
i = i + 1;
}
match;
}
// Alternation
Alternation = Object.subtype(#Alternation);
Alternation.match(stream, context, rules, actions) {
let i = 0;
let success = 0;
while (i < self.length() && success == 0) {
let initialActionCount = actions.length();
let startingPosition = stream.position;
success = self[i].match(stream, context, rules, actions);
if (success == 0) {
while (actions.length() > initialActionCount) {
actions.pop();
}
stream.position = startingPosition;
}
i = i + 1;
}
success;
}
// Action
Action = Object.subtype(#Action);
Action.match(stream, context, rules, actions) {
actions.push([action: self, context: context]);
1;
}
Action.execute(context) {
// Declare all variables that a value is set to in the context
for (statement in self.parseTree.body) {
if (statement.__name__ == "SetVar") {
context.declareVariable(statement.name);
}
}
// Evaluate the parse tree and return to outer context if needed
returnValue = eval(self.parseTree, env: context.variables);
if (context.outerContext != nil) {
context.outerContext.variables[context.returnValueName] = returnValue;
}
}
// Assignment
Assignment = Object.subtype(#Assignment);
Assignment.match(stream, context, rules, actions) {
context.declareVariable(self.name);
innerContext = Context.new(outerContext: context, returnValueName: self.name).init();
self.rule.match(stream, innerContext, rules, actions);
}
// RuleCall
RuleCall = Object.subtype(#RuleCall);
RuleCall.match(stream, context, rules, actions) {
rules[self.name].match(stream, context, rules, actions);
}
// ----- Grammar of Grammars -----
rules = [];
// grammar = - g:mklist
// ( d:definition { g.push(d); }
// ) + end-of-file { print(g, full: Object.new()); }
rules.grammar = Sequence.new()
.push(RuleCall.new(name: #ws))
.push(Assignment.new(name: #g, rule: RuleCall.new(name: #mklist)))
.push(Plus.new(expression: Sequence.new()
.push(Assignment.new(name: #d, rule: RuleCall.new(name: #definition)))
.push(Action.new(parseTree: `{ g[d.name] = d.expression; }))
))
.push(RuleCall.new(name: #end_of_file))
.push(Action.new(parseTree: `{ print(g, full: Object.new()); }));
Definition = Object.subtype(#Definition);
// definition = i:identifier ASSIGN e:expression SEMI? { newDefinition(i, e); }
rules.definition = Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #identifier)))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #expression)))
.push(Optional.new(expression: RuleCall.new(name: #semi)))
.push(Action.new(parseTree: `{ Definition.new(name: i, expression: e); }));
// expression = s1:sequence ( BAR s2:sequence { s1 = newAlternation(s1, s2); }
// ) * { s1; }
rules.expression = Sequence.new()
.push(Assignment.new(name: #s1, rule: RuleCall.new(name: #sequence)))
.push(Action.new(parseTree: `{ s1 = Alternation.new().push(s1); }))
.push(Star.new(expression: Sequence.new()
.push(RuleCall.new(name: #bar))
.push(Assignment.new(name: #s2, rule: RuleCall.new(name: #sequence)))
.push(Action.new(parseTree: `{ s1.push(s2); }))
))
.push(Action.new(parseTree: `{ s1; }));
// sequence = p:prefix
// ( q:prefix { p = newSequence(p, q); }
// ) * { p; }
rules.sequence = Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #prefix)))
.push(Action.new(parseTree: `{ p = Sequence.new().push(p); }))
.push(Star.new(expression: Sequence.new()
.push(Assignment.new(name: #q, rule: RuleCall.new(name: #prefix)))
.push(Action.new(parseTree: `{ p.push(q); }))
))
.push(Action.new(parseTree: `{ p; }));
// prefix = AND action
// |
// ( AND s:suffix { newAnd(s); }
// | NOT s:suffix { newNot(s); }
// | s:suffix { s; }
// )
rules.prefix = Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #and))
.push(RuleCall.new(name: #action))
)
.push(Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #and))
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix)))
.push(Action.new(parseTree: `{ And.new(expression: s); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #not))
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix)))
.push(Action.new(parseTree: `{ Not.new(expression: s); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix)))
.push(Action.new(parseTree: `{ s; }))
)
);
// suffix = p:primary
// ( QUERY { p = newOptional(p); }
// | STAR { p = newStar(p); }
// | PLUS { p = newPlus(p); }
// ) ? { p; }
rules.suffix = Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #primary)))
.push(Optional.new(expression: Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #query))
.push(Action.new(parseTree: `{ p = Optional.new(expression: p); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #star))
.push(Action.new(parseTree: `{ p = Star.new(expression: p); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #plus))
.push(Action.new(parseTree: `{ p = Plus.new(expression: p); }))
)
))
.push(Action.new(parseTree: `{ p; }));
// primary = i1:identifier COLON i2:ruleCallIdent !ASSIGN { newAssignment(i1, i2); }
// | i:ruleCallIdent !ASSIGN { i; }
// | LPAREN e:expression RPAREN { e; }
// | l:literal { l; }
// | c:class { c; }
// | DOT { newDot(); }
// | a:action { a; }
// | BEGIN { newBegin(); }
// | END { newEnd(); }
rules.primary = Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #i1, rule: RuleCall.new(name: #identifier)))
.push(RuleCall.new(name: #colon))
.push(Assignment.new(name: #i2, rule: RuleCall.new(name: #ruleCallIdent)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Action.new(parseTree: `{ Assignment.new(name: i1, rule: i2); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #ruleCallIdent)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Action.new(parseTree: `{ i; }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #lparen))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #expression)))
.push(RuleCall.new(name: #rparen))
.push(Action.new(parseTree: `{ e; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #l, rule: RuleCall.new(name: #literal)))
.push(Action.new(parseTree: `{ l; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #c, rule: RuleCall.new(name: #class)))
.push(Action.new(parseTree: `{ c; }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Action.new(parseTree: `{ Dot.new(); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #action)))
.push(Action.new(parseTree: `{ a; }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #begin))
.push(Action.new(parseTree: `{ Begin.new(); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #end))
.push(Action.new(parseTree: `{ End.new(); }))
);
// identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { newStringEscaped(yytext); }
rules.identifier = Sequence.new()
.push(Begin.new())
.push(CharacterClass.new(value: "-a-zA-Z_"))
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9")))
.push(End.new())
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ yytext }));
// ruleCallIdent = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { newIdentifier(yytext); }
rules.ruleCallIdent = Sequence.new()
.push(Begin.new())
.push(CharacterClass.new(value: "-a-zA-Z_"))
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9")))
.push(End.new())
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ RuleCall.new(name: intern(yytext)); }));
// literal = ['] < ( !['] char )* > ['] - { newStringEscaped(yytext); }
// | ["] < ( !["] char )* > ["] - { newStringEscaped(yytext); }
rules.literal = Alternation.new()
.push(Sequence.new()
.push(CharacterClass.new(value: "\'"))
.push(Begin.new())
.push(Star.new(expression: Sequence.new()
.push(Not.new(expression: CharacterClass.new(value: "\'")))
.push(RuleCall.new(name: #char))
))
.push(End.new())
.push(CharacterClass.new(value: "\'"))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ StringLiteral.new(value: yytext); }))
)
.push(Sequence.new()
.push(CharacterClass.new(value: '\"'))
.push(Begin.new())
.push(Star.new(expression: Sequence.new()
.push(Not.new(expression: CharacterClass.new(value: '\"')))
.push(RuleCall.new(name: #char))
))
.push(End.new())
.push(CharacterClass.new(value: '\"'))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ StringLiteral.new(value: yytext); }))
);
// class = '[' < ( !']' range )* > ']' - { newCharacterClass(yytext); }
rules.class = Sequence.new()
.push(StringLiteral.new(string: "["))
.push(Begin.new())
.push(Star.new(expression: Sequence.new()
.push(Not.new(expression: StringLiteral.new(string: "]")))
.push(RuleCall.new(name: #range))
))
.push(End.new())
.push(StringLiteral.new(string: "]"))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ CharacterClass.new(value: yytext); }));
// range = char '-' char | char
rules.range = Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #char))
.push(StringLiteral.new(string: "-"))
.push(RuleCall.new(name: #char))
)
.push(
RuleCall.new(name: #char)
);
// char = '\\' [abefnrtv'"\[\]\\]
// | '\\' [0-3][0-7][0-7]
// | '\\' [0-7][0-7]?
// | !'\\' .
rules.char = Alternation.new()
.push(Sequence.new()
.push(StringLiteral.new(string: "\\"))
.push(Alternation.new()
.push(CharacterClass.new(value: "abefnrtv\'[]\\"))
.push(CharacterClass.new(value: '\"')) // I hate this
)
)
.push(Sequence.new()
.push(StringLiteral.new(string: "\\"))
.push(CharacterClass.new(value: "0-3"))
.push(CharacterClass.new(value: "0-7"))
.push(CharacterClass.new(value: "0-7"))
)
.push(Sequence.new()
.push(StringLiteral.new(string: "\\"))
.push(CharacterClass.new(value: "0-7"))
.push(Optional.new(expression: CharacterClass.new(value: "0-7")))
)
.push(Sequence.new()
.push(Not.new(expression: StringLiteral.new(string: "\\")))
.push(Dot.new())
);
// action = m:metaBlock - { newAction(m); }
rules.action = Sequence.new()
.push(Assignment.new(name: #m, rule: RuleCall.new(name: #metaBlock)))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ Action.new(parseTree: m); }));
// metaStatement = b:metaBlock { newBlock(b); }
// | e:metaExpression SEMI { e; }
rules.metaStatement = Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #metaBlock)))
.push(Action.new(parseTree: `{ Block.new(b); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(RuleCall.new(name: #semi))
.push(Action.new(parseTree: `{ e; }))
);
// metaExpression = p:metaPrimary
// ( DOT i:metaId ASSIGN e:metaExpression # { $$ = newSetProp(p, i, e) }
// | LBRAK i:metaExpression RBRAK ASSIGN e:metaExpression # { $$ = newSetArray(p, i, e) }
// )
// | i:metaId ASSIGN e:metaExpression { newSetVar(i, e); }
// | pf:metaPostfix { pf; }
rules.metaExpression = Alternation.new(id: 1234)
.push(Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrimary)))
.push(Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
)
.push(Sequence.new()
.push(RuleCall.new(name: #lbrak))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaExpression)))
.push(RuleCall.new(name: #rbrak))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ SetArray.new(object: p, index: i, value: e); }))
)
)
)
.push(Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ SetVar.new(name: i, expr: e); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #pf, rule: RuleCall.new(name: #metaPostfix)))
.push(Action.new(parseTree: `{ pf; }))
);
// metaPostfix = p:metaPrimary
// ( DOT i:id a:args !ASSIGN !LBRACE { p = newInvoke(p, i, a) }
// | DOT i:id !ASSIGN { p = newGetProp(p, i) }
// | a:args !ASSIGN !LBRACE { p = newCall(p, a); }
// ) * { p; }
rules.metaPostfix = Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrimary)))
.push(Star.new(expression: Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #args)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Not.new(expression: RuleCall.new(name: #lbrace)))
.push(Action.new(parseTree: `{ p = Invoke.new(self: p, method: i, arguments: a); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Action.new(parseTree: `{ p = GetProp.new(object: p, key: i); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #args)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Not.new(expression: RuleCall.new(name: #lbrace)))
.push(Action.new(parseTree: `{ p = Call.new(function: p, arguments: a); }))
// TODO: Voir si c'est toujours bon avec le newApply()
)
))
.push(Action.new(parseTree: `{ p; }));
// args = LPAREN a:mklist
// (
// ( k:metaId COLON e:metaExpression { Object_put(a, k, e); }
// | e:metaExpression { Object_push(a, e); }
// )
// ( COMMA
// ( k:metaId COLON e:metaExpression { Object_put(a, k, e); }
// | e:metaExpression { Object_push(a, e); }
// )
// ) *
// ) ? RPAREN { a; }
rules.args = Sequence.new()
.push(RuleCall.new(name: #lparen))
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #mklist)))
.push(Optional.new(expression: Sequence.new()
.push(Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #k, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #colon))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a[k] = e; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a.push(e); }))
)
)
.push(Star.new(expression: Sequence.new()
.push(RuleCall.new(name: #comma))
.push(Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #k, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #colon))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a[k] = e; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a.push(e); }))
)
)
))
))
.push(RuleCall.new(name: #rparen))
.push(Action.new(parseTree: `{ a; }));
// mklist = { new(pObject); }
// metaPrimary = nil | metaVar | metaSubExpr
// metaSubExpr = LPAREN e:metaExpression RPAREN { e; }
rules.mklist = Action.new(parseTree: `{ Object.new(); });
rules.metaPrimary = Alternation.new()
.push(RuleCall.new(name: #nil))
.push(RuleCall.new(name: #metaVar))
.push(RuleCall.new(name: #metaSubExpr));
rules.metaSubExpr = Sequence.new()
.push(RuleCall.new(name: #lparen))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(RuleCall.new(name: #rparen))
.push(Action.new(parseTree = `{ e; }));
// metaBlock = LBRACE b:mklist
// ( e:metaStatement { b.push(e); }
// ) * RBRACE { b; }
rules.metaBlock = Sequence.new()
.push(RuleCall.new(name: #lbrace))
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #mklist)))
.push(
Star.new(
expression: Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaStatement)))
.push(Action.new(parseTree: `{ b.push(e); }))
)
)
.push(RuleCall.new(name: #rbrace))
.push(Action.new(parseTree: `{ b; }));
// metaVar = i:metaId { newGetVar(i); }
// metaId = < LETTER ALNUM* > - { intern(yytext); }
rules.metaVar = Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(Action.new(parseTree: `{ GetVar.new(name: i); }));
rules.metaId = Sequence.new()
.push(Begin.new())
.push(RuleCall.new(name: #letter))
.push(Star.new(expression: RuleCall.new(name: #alnum)))
.push(End.new())
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ intern(yytext); }));
// Literal Terminators
// BAR = '|' -
// NOT = '!' -
// QUERY = '?' -
// BEGIN = '<' -
// END = '>' -
// TILDE = '~' -
// RPERCENT = '%}' -
rules.bar = Sequence.new().push(StringLiteral.new(string: "|")).push(RuleCall.new(name: #ws));
rules.not = Sequence.new().push(StringLiteral.new(string: "!")).push(RuleCall.new(name: #ws));
rules.query = Sequence.new().push(StringLiteral.new(string: "?")).push(RuleCall.new(name: #ws));
rules.begin = Sequence.new().push(StringLiteral.new(string: "<")).push(RuleCall.new(name: #ws));
rules.end = Sequence.new().push(StringLiteral.new(string: ">")).push(RuleCall.new(name: #ws));
rules.tilde = Sequence.new().push(StringLiteral.new(string: "~")).push(RuleCall.new(name: #ws));
rules.rpercent = Sequence.new().push(StringLiteral.new(string: "%}")).push(RuleCall.new(name: #ws));
// DIGIT = [0-9]
// LETTER = [A-Za-z_]
// ALNUM = LETTER | DIGIT
// NIL = "nil" !ALNUM -
rules.digit = CharacterClass.new(value: "0-9");
rules.letter = CharacterClass.new(value: "A-Za-z_");
rules.alnum = Alternation.new()
.push(RuleCall.new(name: #letter))
.push(RuleCall.new(name: #digit));
rules.nil = Sequence.new()
.push(StringLiteral.new(string: "nil"))
.push(Not.new(expression: RuleCall.new(name: #alnum)))
.push(RuleCall.new(name: #ws));
// SEMI = ";" -
// COMMA = "," -
// COLON = ":" -
// LPAREN = "(" -
// RPAREN = ")" -
// LBRAK = "[" -
// RBRAK = "]" -
// LBRACE = "{" -
// RBRACE = "}" -
// ASSIGN = "=" ![=] -
// AND = "&" ![&=] -
// PLUS = "+" ![+=] -
// STAR = "*" ![=] -
// DOT = "." ![.] -
rules.semi = Sequence.new().push(StringLiteral.new(string: ";")).push(RuleCall.new(name: #ws));
rules.comma = Sequence.new().push(StringLiteral.new(string: ",")).push(RuleCall.new(name: #ws));
rules.colon = Sequence.new().push(StringLiteral.new(string: ":")).push(RuleCall.new(name: #ws));
rules.lparen = Sequence.new().push(StringLiteral.new(string: "(")).push(RuleCall.new(name: #ws));
rules.rparen = Sequence.new().push(StringLiteral.new(string: ")")).push(RuleCall.new(name: #ws));
rules.lbrak = Sequence.new().push(StringLiteral.new(string: "[")).push(RuleCall.new(name: #ws));
rules.rbrak = Sequence.new().push(StringLiteral.new(string: "]")).push(RuleCall.new(name: #ws));
rules.lbrace = Sequence.new().push(StringLiteral.new(string: "{")).push(RuleCall.new(name: #ws));
rules.rbrace = Sequence.new().push(StringLiteral.new(string: "}")).push(RuleCall.new(name: #ws));
rules.assign = Sequence.new()
.push(StringLiteral.new(string: "="))
.push(Not.new(expression: CharacterClass.new(value: "=")))
.push(RuleCall.new(name: #ws));
rules.and = Sequence.new()
.push(StringLiteral.new(string: "&"))
.push(Not.new(expression: CharacterClass.new(value: "&=")))
.push(RuleCall.new(name: #ws));
rules.plus = Sequence.new()
.push(StringLiteral.new(string: "+"))
.push(Not.new(expression: CharacterClass.new(value: "+=")))
.push(RuleCall.new(name: #ws));
rules.star = Sequence.new()
.push(StringLiteral.new(string: "*"))
.push(Not.new(expression: CharacterClass.new(value: "=")))
.push(RuleCall.new(name: #ws));
rules.dot = Sequence.new()
.push(StringLiteral.new(string: "."))
.push(Not.new(expression: CharacterClass.new(value: ".")))
.push(RuleCall.new(name: #ws));
// Whitespace
// - = ( space | comment )*
// space = ' ' | '\t' | end-of-line
// comment = '#' ( !end-of-line . )* end-of-line
// end-of-line = '\r\n' | '\n' | '\r'
// end-of-file = !.
rules.end_of_file = Not.new(expression: Dot.new());
rules.end_of_line = Alternation.new()
.push(StringLiteral.new(string: "\r\n"))
.push(StringLiteral.new(string: "\n"))
.push(StringLiteral.new(string: "\r"));
rules.comment = Sequence.new()
.push(StringLiteral.new(string: "#"))
.push(Star.new(expression:
Sequence.new()
.push(Not.new(expression: RuleCall.new(name: #end_of_line)))
.push(Dot.new())
))
.push(RuleCall.new(name: #end_of_line));
rules.space = Alternation.new()
.push(StringLiteral.new(string: " "))
.push(StringLiteral.new(string: "\t"))
.push(RuleCall.new(name: #end_of_line));
rules.ws = Star.new(expression: Alternation.new()
.push(RuleCall.new(name: #space))
.push(RuleCall.new(name: #comment))
);
// ----- Main -----
stream = newStream(readfile("rawgrammar.leg"));
//stream = newStream("rule1 = rule2* | b:rule3 {a = b;} rule4 = 'hello' ");
context = Context.new(outerContext: nil).init();
actions = [];
print("\nMatching : ", rules.grammar.match(stream, context, rules, actions), "\n");
// Execute all actions after all matching
for (actionAndContext in actions) {
//println(actionAndContext.action.parseTree);
actionAndContext.action.execute(actionAndContext.context);
}
println();

+ 431
- 204
minproto.leg Parādīt failu

@ -1,9 +1,11 @@
# minproto.leg -- minimal prototype langauge for semantic experiments
#
# last edited: 2024-05-14 12:14:06 by piumarta on zora
# last edited: 2024-05-15 19:13:04 by piumarta on debian
%{
;
//#define YY_DEBUG 1
#ifndef GC
# define GC 1 // do not fill memory with unreachable junk
#endif
@ -97,9 +99,9 @@ oop printOn(oop buf, oop obj, int indent);
#endif
#if PRIMCLOSURE
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal)
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Range)
#else
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure)
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure) _(Range)
#endif
#define declareProto(NAME) oop p##NAME = 0;
@ -127,7 +129,7 @@ doTypes(makeProto);
doProperties(declareProp);
#undef declareProp
#define doSymbols(_) _(t) _(name) _(expr) _(function) _(arguments) _(object) _(index) _(key) _(value) _(self) _(method) _(parameters) _(body) _(lambda) _(environment) _(operation) _(full) _(condition) _(consequent) _(alternate) _(expression) _(identifier) _(initialise) _(update) _(first) _(last) _(fixed) _(keyvals) _(__globals__)
#define doSymbols(_) _(t) _(name) _(expr) _(function) _(arguments) _(object) _(index) _(key) _(value) _(self) _(method) _(parameters) _(body) _(lambda) _(environment) _(operation) _(full) _(condition) _(consequent) _(alternate) _(expression) _(identifier) _(initialise) _(update) _(first) _(last) _(fixed) _(keyvals) _(__globals__) _(start) _(end) _(env)
#define declareSym(NAME) oop sym_##NAME = 0;
doSymbols(declareSym);
@ -470,10 +472,10 @@ int stringLength(oop obj, char *who)
return 0;
}
oop newPrimitive(prim_t function)
oop newPrimitive(prim_t function, oop name)
{
oop obj = make(Primitive);
_set(obj, Primitive,name, 0);
_set(obj, Primitive,name, name);
_set(obj, Primitive,function, function);
return obj;
}
@ -783,6 +785,119 @@ oop newObjectWith(int isize, oop *indexed, int psize, struct property *propertie
return obj;
}
int isSpecial(oop key)
{
return is(Symbol, key) && !strncmp("__", _get(key, Symbol,name), 2);
}
oop keys(oop self, int all)
{
oop keys = new(pObject);
# if DELOPT
if (all && nil != _getDelegate(self)) Object_push(keys, prop_delegate);
# endif
switch (getType(self)) {
case Undefined: case Integer: case Float: case String: case Symbol: case Primitive:
break;
# if PRIMCLOSURE
case Lambda: {
Object_push(keys, sym_parameters);
Object_push(keys, sym_body);
break;
}
case Closure: {
Object_push(keys, sym_fixed);
Object_push(keys, sym_lambda);
Object_push(keys, sym_environment);
break;
}
# endif
case Object: {
int size = _get(self, Object,psize);
struct property *kvs = _get(self, Object,properties);
for (int i = 0; i < size; ++i) {
oop key = kvs[i].key;
if (all || !isSpecial(key)) Object_push(keys, key);
}
break;
}
}
return keys;
}
intptr_t cmp(oop l, oop r, char *who)
{
int tl = getType(l), tr = getType(r);
if (Integer == tl && Integer == tr) return _integerValue(l) - _integerValue(r);
if (Float == tl || Float == tr) return floatValue(l, who) - floatValue(r, who);
if (String == tl && String == tr) {
int ll = _get(l, String,length), rr = _get(r, String,length);
if (ll == rr) return strncmp(_get(l, String,value), _get(r, String,value), ll);
return ll - rr;
}
if (Symbol == tl && Symbol == tr) return strcmp(stringValue(l, who), stringValue(r, who));
return (intptr_t)l - (intptr_t)r;
}
#if defined (__linux__)
int objcmp(const void *a, const void *b, void *who) { return cmp(*(oop *)a, *(oop *)b, who); }
#else
int objcmp(void *who, const void *a, const void *b) { return cmp(*(oop *)a, *(oop *)b, who); }
#endif
oop sortObject(oop obj, char *who)
{ assert(is(Object, obj));
# if defined(__linux__)
qsort_r(_get(obj, Object,indexed), _get(obj, Object,isize), sizeof(oop), objcmp, "sort");
# else
qsort_r(_get(obj, Object,indexed), _get(obj, Object,isize), sizeof(oop), "sort", objcmp);
# endif
return obj;
}
int chrcmp(const void *a, const void *b) { return *(char *)a - *(char *)b; }
oop sortString(oop obj)
{ assert(is(String, obj));
qsort(_get(obj, String,value), _get(obj, String,length), 1, chrcmp);
return obj;
}
oop clone(oop obj) // shallow copy
{
switch (getType(obj)) {
case String: return newStringLen(_get(obj, String,value), _get(obj, String,length));
case Object:{
oop clone = new(_getDelegate(obj));
oop *elts = _get(obj, Object,indexed);
int size = _get(obj, Object,isize);
for (int i = 0; i < size; ++i) Object_push(clone, elts[i]);
struct property *kvs = _get(obj, Object,properties);
size = _get(obj, Object,psize);
for (int i = 0; i < size; ++i) {
oop key = kvs[i].key;
if (prop_delegate == key) continue;
Object_put(clone, key, kvs[i].val);
}
return clone;
}
default: break;
}
return obj;
}
oop sorted(oop obj, char *who)
{
switch (getType(obj)) {
case String: return sortString(clone(obj));
case Object: return sortObject(clone(obj), who);
default: break;
}
fatal("sort: cannot sort %s", getTypeName(obj));
return 0;
}
oop apply(oop func, oop self, oop args, oop env);
void codeParametersOn(oop str, oop object, char *begin, char *end)
@ -822,7 +937,7 @@ oop codeOn(oop str, oop obj, int indent)
case Symbol: String_format(str, "#%s", _get(obj, Symbol,name)); break;
case Primitive: {
String_appendAll(str, "<primitive ");
if (_get(obj, Primitive,name)) codeOn(str, _get(obj, Primitive,name), indent);
if (_get(obj, Primitive,name)) printOn(str, _get(obj, Primitive,name), 0);
else String_format(str, "%p", _get(obj, Primitive,function));
String_append(str, '>');
break;
@ -851,17 +966,97 @@ oop codeOn(oop str, oop obj, int indent)
return str;
}
void indentOn(oop buf, int indent)
{
if (indent < 1) return;
String_append(buf, '\n');
for (int i = indent; i--;) String_appendAll(buf, " | ");
String_appendAll(buf, " ");
}
void printObjectNameOn(oop buf, oop obj, int indent)
{
int level = 0;
oop proto = obj;
oop name = nil;
do {
++level;
name = Object_getLocal(proto, prop_name);
if (nil != name) break;
proto = _getDelegate(proto);
} while (is(Object, proto));
for (int i = level; i--;) String_append(buf, '<');
if (name != nil) printOn(buf, name, 0);
else String_appendAll(buf, "?");
for (int i = level; i--;) String_append(buf, '>');
}
enum {
NO_DELEGATE = -1,
NO_SPECIALS = -2,
};
int printObjectPropertiesOn(oop buf, oop obj, int indent)
{
oop names = sortObject(keys(obj, indent > 0), "print");
int nkeys = _get(names, Object,isize);
oop *elts = _get(names, Object,indexed);
int i = 0;
for (i = 0; i < nkeys; ++i) {
if (i && indent < 1) String_appendAll(buf, ", ");
oop key = elts[i];
if (prop_delegate == key) continue;
indentOn(buf, indent);
printOn(buf, key, 0);
String_appendAll(buf, ": ");
printOn(buf, Object_getLocal(obj, key), indent + (indent >= 0));
}
return i;
}
oop printOn(oop buf, oop obj, int indent)
{
switch (getType(obj)) {
case Undefined: String_appendAll(buf, "nil"); break;
case Integer: String_format(buf, "%ld", _integerValue(obj)); break;
case Float: String_format(buf, "%f" , _floatValue(obj)); break;
case String: String_format(buf, "%.*s", (int)_get(obj, String,length), _get(obj, String,value)); break;
case Symbol: String_appendAll(buf, _get(obj, Symbol,name)); break;
case Undefined: String_appendAll(buf, "nil"); break;
case Integer: String_format(buf, "%ld", _integerValue(obj)); break;
case Float: String_format(buf, "%f" , _floatValue(obj)); break;
case String: {
char *str = _get(obj, String,value);
int len = _get(obj, String,length);
if (indent && indent != 1) {
String_append(buf, '"');
while (len--) {
int c = *str++;
if (c >= ' ' && c <= '~') String_append(buf, c);
else if (c == '"') String_appendAll(buf, "\\\"");
else if (c == '\\') String_appendAll(buf, "\\\\");
else {
switch (c) {
case '\a': c = 'a'; break;
case '\b': c = 'b'; break;
case '\f': c = 'f'; break;
case '\n': c = 'n'; break;
case '\r': c = 'r'; break;
case '\t': c = 't'; break;
case '\v': c = 'v'; break;
defalt: String_format(buf, "\\%03o", c); continue;
}
String_format(buf, "\\%c", c);
}
}
String_append(buf, '"');
return buf;
}
String_format(buf, "%.*s", len, str);
break;
}
case Symbol:
if (indent < 0) String_append(buf, '#');
String_appendAll(buf, _get(obj, Symbol,name));
break;
case Primitive: {
String_appendAll(buf, "<primitive ");
if (_get(obj, Primitive,name)) printOn(buf, _get(obj, Primitive,name), indent);
if (_get(obj, Primitive,name)) printOn(buf, _get(obj, Primitive,name), 0);
else String_format(buf, "%p", _get(obj, Primitive,function));
String_append(buf, '>');
break;
@ -869,65 +1064,40 @@ oop printOn(oop buf, oop obj, int indent)
#if PRIMCLOSURE
case Lambda: {
String_appendAll(buf, "<<Lambda>>");
if (!indent) break;
if (indent < 1) break;
String_append(buf, '\n');
for (int j = indent; j--;) String_appendAll(buf, " | ");
indentOn(buf, indent);
String_appendAll(buf, " body: ");
printOn(buf, _get(obj, Lambda,body), indent+1);
printOn(buf, _get(obj, Lambda,body), indent + 1);
String_append(buf, '\n');
for (int j = indent; j--;) String_appendAll(buf, " | ");
String_appendAll(buf, " parameters: ");
printOn(buf, _get(obj, Lambda,parameters), indent+1);
printOn(buf, _get(obj, Lambda,parameters), indent + 1);
break;
}
case Closure: {
String_appendAll(buf, "<<Closure>>");
if (!indent) break;
if (indent < 1) break;
String_append(buf, '\n');
for (int j = indent; j--;) String_appendAll(buf, " | ");
String_appendAll(buf, " environment: ");
printOn(buf, _get(obj, Closure,environment), indent+1);
printOn(buf, _get(obj, Closure,environment), indent + 1);
String_append(buf, '\n');
for (int j = indent; j--;) String_appendAll(buf, " | ");
String_appendAll(buf, " function: ");
printOn(buf, _get(obj, Closure,function), indent+1);
printOn(buf, _get(obj, Closure,function), indent + 1);
break;
break;
}
#endif
case Object: {
int level = 0;
oop proto = obj;
oop name = nil;
do {
++level;
name = Object_getLocal(proto, prop_name);
if (nil != name) break;
proto = _getDelegate(proto);
} while (is(Object, proto));
for (int i = level; i--;) String_append(buf, '<');
if (name != nil)
printOn(buf, name, indent);
else
String_appendAll(buf, "?");
for (int i = level; i--;) String_append(buf, '>');
printObjectNameOn(buf, obj, indent);
if (!indent) break;
for (;;) {
int psize = _get(obj, Object,psize);
struct property *props = _get(obj, Object,properties);
for (int i = 0; i < psize; ++i) {
if (prop_delegate == props[i].key) continue;
String_append(buf, '\n');
for (int j = indent; j--;) String_appendAll(buf, " | ");
String_appendAll(buf, " ");
printOn(buf, props[i].key, indent+1);
String_appendAll(buf, ": ");
printOn(buf, props[i].val, indent+1);
}
printObjectPropertiesOn(buf, obj, indent);
int isize = _get(obj, Object,isize);
oop *indexed = _get(obj, Object,indexed);
for (int i = 0; i < isize; ++i) {
@ -1170,18 +1340,18 @@ oop GetVar_eval(oop exp, oop env) { return getvar(env, Object_get(
void GetVar_codeOn(oop exp, oop str, oop env) { printOn(str, Object_get(exp, sym_name), 0); }
oop newSetVar(oop name, oop expr)
oop newSetVar(oop name, oop value)
{
oop o = new(pSetVar);
Object_put(o, sym_name, name);
Object_put(o, sym_expr, expr);
Object_put(o, sym_name, name);
Object_put(o, sym_value, value);
return o;
}
oop SetVar_eval(oop exp, oop env)
{
oop key = Object_get(exp, sym_name) ;
oop val = eval(Object_get(exp, sym_expr), env);
oop key = Object_get(exp, sym_name ) ;
oop val = eval(Object_get(exp, sym_value), env);
return setvar(env, key, val);
}
@ -1189,7 +1359,7 @@ void SetVar_codeOn(oop exp, oop str, oop env)
{
printOn(str, Object_get(exp, sym_name), 0);
String_appendAll(str, " = ");
codeOn(str, Object_get(exp, sym_expr), 0);
codeOn(str, Object_get(exp, sym_value), 0);
}
oop newRefProp(oop object, oop key)
@ -1352,6 +1522,17 @@ oop GetArray_eval(oop exp, oop env)
default: fatal("[]: %s is not indexable", storeString(obj, 0));
}
}
if (getType(ind) == Object && Object_get(ind, prop_name) == Object_get(pRange, prop_name)) {
switch (getType(obj)) {
case String: {
int start = integerValue(eval(Object_get(ind, sym_start), env), "[..]");
int end = integerValue(eval(Object_get(ind, sym_end ), env), "[..]");
oop slice = newStringLen(String_aref(obj, start), end - start);
return slice;
}
default: fatal("[]: %s is not range - indexable", storeString(obj, 0));
}
}
if (!is(Object, obj)) fatal("[]: %s is not an object", storeString(obj, 0));
return Object_getLocal(obj, ind);
}
@ -1401,6 +1582,25 @@ void SetArray_codeOn(oop exp, oop str, oop env)
codeOn(str, Object_get(exp, sym_value), 0);
}
oop newRange(oop start, oop end) {
oop o = new(pRange);
Object_put(o, sym_start, start);
Object_put(o, sym_end, end);
return o;
}
oop Range_eval(oop exp, oop env)
{
return exp;
}
void Range_codeOn(oop exp, oop str, oop env)
{
codeOn(str, Object_get(exp, sym_start), 0);
String_appendAll(str, "..");
codeOn(str, Object_get(exp, sym_end), 0);
}
oop newCall(oop function, oop arguments)
{
oop o = new(pCall);
@ -1618,6 +1818,7 @@ void Closure_codeOn(oop exp, oop str, oop env)
_(Add, +) _(Sub, -) \
_(Mul, *) _(Div, /) _(Mod, %) \
_(PostAdd, ++) _(PostDec, --) \
_(PreSet, =) \
_(PreOr, |=) _(PreXor, ^=) _(PreAnd, &=) \
_(PreShl, >>=) _(PreShr, <<=) \
_(PreAdd, +=) _(PreSub, -=) \
@ -1675,20 +1876,6 @@ binop(binBitAnd, &);
#undef binop
intptr_t cmp(oop l, oop r, char *who)
{
int tl = getType(l), tr = getType(r);
if (Integer == tl && Integer == tr) return _integerValue(l) - _integerValue(r);
if (Float == tl || Float == tr) return floatValue(l, who) - floatValue(r, who);
if (String == tl && String == tr) {
int ll = _get(l, String,length), rr = _get(r, String,length);
if (ll == rr) return strncmp(_get(l, String,value), _get(r, String,value), ll);
return ll - rr;
}
if (Symbol == tl && Symbol == tr) return strcmp(stringValue(l, who), stringValue(r, who));
return (intptr_t)l - (intptr_t)r;
}
#define newBoolean(TF) ((TF) ? sym_t : nil)
#define binop(NAME, OP) \
@ -1735,6 +1922,12 @@ oop binPostDec(oop lhs, oop rhs)
return value;
}
oop binPreSet(oop lhs, oop rhs)
{ assert(isInteger(lhs));
oop *ref = (oop *)(intptr_t)_integerValue(lhs); assert(isInteger(rhs));
return *ref = rhs;
}
#define binop(NAME, OP) \
oop NAME(oop lhs, oop rhs) \
{ assert(isInteger(lhs)); \
@ -1914,6 +2107,10 @@ oop Binop_eval(oop exp, oop env)
}
return value;
}
case opPreSet: { assert(isInteger(lhs)); // ref
oop *ref = (oop *)(intptr_t)_integerValue(lhs);
return *ref = rhs;
}
case opPreOr ... opPreMod: { assert(isInteger(lhs)); // ref
oop *ref = (oop *)(intptr_t)_integerValue(lhs);
oop val = *ref; assert(isInteger(rhs)); // delta
@ -2482,6 +2679,31 @@ void Literal_codeOn(oop exp, oop str, oop env)
# endif
}
oop lvalue(oop rval)
{
if (!is(Object,rval)) fatal("cannot assign to: %s", codeString(rval, 0));
oop kind = _getDelegate(rval);
if (kind == pGetVar ) kind = pRefVar;
else if (kind == pGetProp ) kind = pRefProp;
else if (kind == pGetArray) kind = pRefArray;
else fatal("cannot assign to: %s", codeString(rval, 0));
_setDelegate(rval, kind);
return rval;
}
oop assign(oop rval, oop value)
{
if (!is(Object,rval)) fatal("cannot assign to: %s", codeString(rval, 0));
oop kind = _getDelegate(rval);
if (kind == pGetVar ) kind = pSetVar;
else if (kind == pGetProp ) kind = pSetProp;
else if (kind == pGetArray) kind = pSetArray;
else fatal("cannot assign to: %s", codeString(rval, 0));
_setDelegate(rval, kind);
Object_put(rval, sym_value, value);
return rval;
}
%}
@ -2521,23 +2743,19 @@ proto = v:var ( DOT j:id !LPAREN { v = newGetProp(v, j) }
EOS = SEMI+ | &RBRACE | &ELSE
expr = p:postfix
( DOT i:id ASSIGN e:expr { $$ = newSetProp(p, i, e) }
| LBRAK i:expr RBRAK ASSIGN e:expr { $$ = newSetArray(p, i, e) }
)
| i:id ASSIGN e:expr { $$ = newSetVar(i, e) }
| l:lvalue ( PLUSEQ r:expr { $$ = newBinop(opPreAdd, l, r) }
| MINUSEQ r:expr { $$ = newBinop(opPreSub, l, r) }
| STAREQ r:expr { $$ = newBinop(opPreMul, l, r) }
| SLASHEQ r:expr { $$ = newBinop(opPreDiv, l, r) }
| PCENTEQ r:expr { $$ = newBinop(opPreMod, l, r) }
| SHLEQ r:expr { $$ = newBinop(opPreShl, l, r) }
| SHREQ r:expr { $$ = newBinop(opPreShr, l, r) }
| ANDEQ r:expr { $$ = newBinop(opPreAnd, l, r) }
| XOREQ r:expr { $$ = newBinop(opPreXor, l, r) }
| OREQ r:expr { $$ = newBinop(opPreOr, l, r) }
)
| logor
expr = i:id ASSIGN e:expr { $$ = newSetVar(i, 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 }
@ -2572,13 +2790,16 @@ sum = l:prod ( PLUS r:prod { l = newBinop(opAdd, l, r) }
| MINUS r:prod { l = newBinop(opSub, l, r) }
)* { $$ = l }
prod = l:prefix ( STAR r:prefix { l = newBinop(opMul, l, r) }
| SLASH r:prefix { l = newBinop(opDiv, l, r) }
| PCENT r:prefix { l = newBinop(opMod, 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 }
prefix = PPLUS l:lvalue { $$ = newBinop(opPreAdd, l, newInteger(1)) }
| MMINUS l:lvalue { $$ = newBinop(opPreSub, l, newInteger(1)) }
range = i1:prefix ( DOTDOT i2:prefix { i1 = newRange(i1, i2) }
) ? { $$ = i1 }
prefix = PPLUS p:prefix { $$ = newBinop(opPreAdd, lvalue(p), newInteger(1)) }
| MMINUS p:prefix { $$ = newBinop(opPreSub, lvalue(p), newInteger(1)) }
| PLING p:prefix { $$ = newUnyop(opNot, p) }
| MINUS p:prefix { $$ = newUnyop(opNeg, p) }
| TILDE p:prefix { $$ = newUnyop(opCom, p) }
@ -2586,41 +2807,35 @@ prefix = PPLUS l:lvalue { $$ = newBinop(opPreAdd, l, new
| COMMAT e:expr { $$ = newUnyop(opUnquote, e) }
| postfix
lvalue =
l:primary
( LBRAK e:expr RBRAK &(DOT | LBRAK | LPAREN) { l = newGetArray(l, e) }
| DOT i:id a:args &(DOT | LBRAK | LPAREN) { l = newInvoke(l, i, a) }
| DOT i:id &(DOT | LBRAK | LPAREN) { l = newGetProp(l, i) }
| a:args &(DOT | LBRAK | LPAREN) { l = newApply(l, a) }
postfix = p:primary
( LBRAK e:expr RBRAK { p = newGetArray(p, e) }
| DOT i:id ( a:args !LBRACE { p = newInvoke(p, i, a) }
| { p = newGetProp(p, i) }
)
| a:args !LBRACE { p = newApply(p, a) }
)*
( LBRAK e:expr RBRAK { l = newRefArray(l, e) }
| DOT i:id { l = newRefProp(l, i) }
) { $$ = l }
|
i:id { $$ = newRefVar(i) }
postfix = l:lvalue ( PPLUS { $$ = newBinop(opPostAdd, l, newInteger( 1)) }
| MMINUS { $$ = newBinop(opPostAdd, l, newInteger(-1)) }
)
| p:primary
( LBRAK e:expr RBRAK !ASSIGN { p = newGetArray(p, e) }
| DOT i:id a:args !ASSIGN !LBRACE { p = newInvoke(p, i, a) }
| DOT i:id !ASSIGN { p = newGetProp(p, i) }
| a:args !ASSIGN !LBRACE { p = newApply(p, a) }
)* { $$ = p }
( PPLUS { p = newBinop(opPostAdd, lvalue(p), newInteger( 1)) }
| MMINUS { p = newBinop(opPostAdd, lvalue(p), newInteger(-1)) }
)? { $$ = p }
args = LPAREN a:mkobj
( ( k:id COLON e:expr { Object_put(a, k, e) }
| e:expr { Object_push(a, e) }
( RPAREN
| ( k:id COLON e:expr { Object_put(a, k, e) }
| e:expr { Object_push(a, e) }
)
( COMMA ( k:id COLON e:expr { Object_put(a, k, e) }
| e:expr { Object_push(a, e) }
) )* )? RPAREN { $$ = a }
( COMMA ( k:id COLON e:expr { Object_put(a, k, e) }
| e:expr { Object_push(a, e) }
) )* RPAREN ) { $$ = a }
params = LPAREN p:mkobj
( i:id { Object_push(p, i) }
( COMMA i:id { Object_push(p, i) }
)* )? RPAREN { $$ = p }
( RPAREN
| i:id ( COLON e:expr { Object_put(p, i, e) }
| { Object_push(p, i) }
)
( COMMA i:id ( COLON e:expr { Object_put(p, i, e) }
| { Object_push(p, i) }
)
)* RPAREN ) { $$ = p }
mkobj = { $$ = new(pObject) }
@ -2632,11 +2847,12 @@ subexpr = LPAREN e:expr RPAREN { $$ = e }
| b:block { $$ = newBlock(b) }
literal = LBRAK o:mkobj
( ( i:id COLON e:expr { Object_put(o, i, e) }
| e:expr { Object_push(o, e) }
) ( COMMA ( i:id COLON e:expr { Object_put(o, i, e) }
| e:expr { Object_push(o, e) }
) )* )? RBRAK { $$ = newLiteral(o) }
( RBRAK
| ( ( i:id COLON e:expr { Object_put(o, i, e) }
| e:expr { Object_push(o, e) }
) ( COMMA ( i:id COLON e:expr { Object_put(o, i, e) }
| e:expr { Object_push(o, e) }
) )* )? RBRAK ) { $$ = newLiteral(o) }
block = LBRACE b:mkobj
( e:stmt { Object_push(b, e) }
@ -2644,19 +2860,24 @@ block = LBRACE b:mkobj
nil = NIL { $$ = nil }
number = "-" u:unsign { $$ = neg(u) }
| "+" n:number { $$ = u }
| u:unsign { $$ = u }
number = "-" n:unsign { $$ = neg(n) }
| "+" n:number { $$ = n }
| n:unsign { $$ = n }
unsign = < DIGIT+ '.' DIGIT* EXP? > - { $$ = newFloat(strtod(yytext, 0)) }
| < DIGIT* '.' DIGIT+ EXP? > - { $$ = newFloat(strtod(yytext, 0)) }
unsign = < DIGIT* '.' DIGIT+ EXP? > - { $$ = newFloat(strtod(yytext, 0)) }
| "0" [bB] < BIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 2)) }
| "0" [xX] < HIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 16)) }
| "0" < OIGIT* > - { $$ = newInteger(strtol(yytext, 0, 8)) }
| < DIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 10)) }
string = '"' < ( !'"' . )* > '"' - { $$ = newStringEscaped(yytext) }
| "'" < ( !"'" . )* > "'" - { $$ = newStringEscaped(yytext) }
string = '"' < ( !'"' char )* > '"' - { $$ = newStringEscaped(yytext) }
| "'" < ( !"'" char )* > "'" - { $$ = newStringEscaped(yytext) }
char = "\\" ( ["'\\abfnrtv]
| [xX] HIGIT*
| [0-7][0-7]?[0-7]?
)
| .
symbol = HASH i:id { $$ = i }
@ -2734,7 +2955,8 @@ SLASH = "/" ![/=] -
SLASHEQ = "/=" -
PCENT = "%" ![=] -
PCENTEQ = "%=" -
DOT = "." -
DOT = "." ![.] -
DOTDOT = ".." -
PLING = "!" ![=] -
TILDE = "~" -
@ -2794,8 +3016,15 @@ oop apply(oop func, oop self, oop args, oop env)
case NLR_RETURN: return nlrPop();
}
# endif
// positional args -> named parameters
for (int i = 0; i < nparam; ++i)
Object_put(args, pparam[i], i < nargs ? pargs[i] : nil);
// keyword defaults
int nkeywd = _get(parameters, Object,psize);
struct property *pkeywd = _get(parameters, Object,properties);
for (int i = 0; i < nkeywd; ++i)
if (Object_find(args, pkeywd[i].key) < 0)
Object_put(args, pkeywd[i].key, eval(pkeywd[i].val, args));
for (int i = 0; i < size; ++i)
result = eval(exprs[i], args);
# if NONLOCAL
@ -2930,57 +3159,23 @@ oop prim_length(oop func, oop self, oop args, oop env)
return newInteger(_get(self, Object,isize));
}
oop sortObject(oop obj, char *who)
oop prim_keys(oop func, oop self, oop args, oop env)
{
int limit = _get(obj, Object,isize);
oop *elts = _get(obj, Object,indexed);
for (int i = 0; i < limit - 1; ++i) {
int mindex = i;
oop minobj = elts[i];
for (int j = i + 1; j < limit; ++j) {
oop newobj = elts[j];
if (cmp(newobj, minobj, who) < 0) mindex = j, minobj = newobj;
}
if (mindex != i) {
oop tmpobj = elts[i];
elts[i] = minobj;
elts[mindex] = tmpobj;
}
}
return obj;
return keys(self, 0);
}
oop prim_keys(oop func, oop self, oop args, oop env)
oop prim_allKeys(oop func, oop self, oop args, oop env)
{
oop keys = new(pObject);
# if DELOPT
if (nil != _getDelegate(self)) Object_push(keys, prop_delegate);
# endif
switch (getType(self)) {
case Undefined: case Integer: case Float: case String: case Symbol: case Primitive:
break;
case Object: {
int size = _get(self, Object,psize);
struct property *kvs = _get(self, Object,properties);
for (int i = 0; i < size; ++i) Object_push(keys, kvs[i].key);
sortObject(keys, "keys");
break;
}
# if PRIMCLOSURE
case Lambda: {
Object_push(keys, sym_parameters);
Object_push(keys, sym_body);
break;
}
case Closure: {
Object_push(keys, sym_fixed);
Object_push(keys, sym_lambda);
Object_push(keys, sym_environment);
break;
}
# endif
return keys(self, 1);
}
oop prim_sorted(oop func, oop self, oop args, oop env)
{ assert(is(Object, args));
if (self == nil) {
if (_get(args, Object,isize) != 1) fatal("sorted: one argument expected");
self = _get(args, Object,indexed)[0];
}
return keys;
return sorted(self, "sorted");
}
oop prim_env(oop func, oop self, oop args, oop env)
@ -2993,6 +3188,11 @@ oop prim_eval(oop func, oop self, oop args, oop env)
int argc = _get(args, Object,isize);
oop *indexed = _get(args, Object,indexed);
oop result = nil;
if (nil != Object_getLocal(args, sym_env)) {
env = Object_getLocal(args, sym_env);
}
for (int i = 0; i < argc; ++i) result = eval(indexed[i], env);
return result;
}
@ -3002,13 +3202,29 @@ oop prim___eval__(oop func, oop self, oop args, oop env)
return self;
}
oop prim_intern(oop func, oop self, oop args, oop env)
{
int argc = _get(args, Object,isize);
oop *indexed = _get(args, Object,indexed);
oop result = nil;
if (argc != 1) {
fatal("intern: invalid number of arguments");
}
if (getType(indexed[0]) != String) {
fatal("intern: argument is not of type String, got %s instead", getTypeName(indexed[0]));
}
return intern(_get(indexed[0], String, value));
}
oop prim_print(oop func, oop self, oop args, oop env)
{
int argc = _get(args, Object,isize);
oop *indexed = _get(args, Object,indexed);
oop result = nil;
int indent = 0;
if (nil != Object_getLocal(args, sym_full)) indent = 1;
oop full = Object_getLocal(args, sym_full);
int indent = isInteger(full) ? _integerValue(full) : nil != full;
for (int i = 0; i < argc; ++i) print(result = indexed[i], indent);
fflush(stdout);
return nil;
@ -3137,7 +3353,7 @@ oop prim_exit(oop func, oop self, oop args, oop env)
oop replFile(FILE *in)
{
int oldline = lineno;
lineno = 0;
lineno = 1;
input = newInput();
readFile(in, &input->text, &input->size);
oop result = nil;
@ -3203,7 +3419,7 @@ int main(int argc, char **argv)
# undef defineProto
Object_put(pObject, prop_eval, newPrimitive(prim___eval__)); // inherited by all objects
Object_put(pObject, prop_eval, newPrimitive(prim___eval__, newString("Object.__eval__"))); // inherited by all objects
#if TYPECODES
@ -3212,7 +3428,7 @@ int main(int argc, char **argv)
#else // !TYPECODES
# define defineEvaluator(NAME) \
Object_put(p##NAME, prop_eval, newPrimitive(prim_##NAME##_eval));
Object_put(p##NAME, prop_eval, newPrimitive(prim_##NAME##_eval, newString(#NAME".__eval__")));
#endif // !TYPECODES
@ -3221,7 +3437,7 @@ int main(int argc, char **argv)
# undef defineEvaluator
# define defineCodeOn(NAME) \
Object_put(p##NAME, prop_codeon, newPrimitive(prim_##NAME##_codeOn));
Object_put(p##NAME, prop_codeon, newPrimitive(prim_##NAME##_codeOn, newString(#NAME".codeOn")));
doProtos(defineCodeOn);
@ -3229,26 +3445,37 @@ int main(int argc, char **argv)
macros = Object_put(pSymbol, intern("macros"), new(pObject));
_set(intern("__env__" ), Symbol,value, newPrimitive(prim_env));
_set(intern("eval" ), Symbol,value, newPrimitive(prim_eval));
_set(intern("print" ), Symbol,value, newPrimitive(prim_print));
_set(intern("codeString" ), Symbol,value, newPrimitive(prim_codeString));
_set(intern("sqrt" ), Symbol,value, newPrimitive(prim_sqrt));
_set(intern("round" ), Symbol,value, newPrimitive(prim_round));
_set(intern("truncate" ), Symbol,value, newPrimitive(prim_truncate));
_set(intern("cputime" ), Symbol,value, newPrimitive(prim_cputime));
_set(intern("evaluations"), Symbol,value, newPrimitive(prim_evaluations));
_set(intern("len" ), Symbol,value, newPrimitive(prim_len));
_set(intern("ord" ), Symbol,value, newPrimitive(prim_ord));
_set(intern("chr" ), Symbol,value, newPrimitive(prim_chr));
_set(intern("readfile" ), Symbol,value, newPrimitive(prim_readfile));
_set(intern("exit" ), Symbol,value, newPrimitive(prim_exit));
Object_put(pObject, intern("new"), newPrimitive(prim_new ));
Object_put(pObject, intern("push"), newPrimitive(prim_push ));
Object_put(pObject, intern("pop"), newPrimitive(prim_pop ));
Object_put(pObject, intern("length"), newPrimitive(prim_length));
Object_put(pObject, intern("keys"), newPrimitive(prim_keys ));
# define prim(NAME, FUNC) _set(intern(#NAME), Symbol,value, newPrimitive(FUNC, newString(#NAME)))
prim(__env__ , prim_env);
prim(eval , prim_eval);
prim(print , prim_print);
prim(codeString , prim_codeString);
prim(sqrt , prim_sqrt);
prim(round , prim_round);
prim(truncate , prim_truncate);
prim(cputime , prim_cputime);
prim(evaluations, prim_evaluations);
prim(len , prim_len);
prim(ord , prim_ord);
prim(chr , prim_chr);
prim(readfile , prim_readfile);
prim(exit , prim_exit);
prim(intern , prim_intern);
# undef prim
# define method(CLASS, NAME, FUNC) Object_put(p##CLASS, intern(#NAME), newPrimitive(FUNC, newString(#CLASS"."#NAME)))
method(Object,new, prim_new );
method(Object,push, prim_push );
method(Object,pop, prim_pop );
method(Object,length, prim_length );
method(Object,keys, prim_keys );
method(Object,allKeys, prim_allKeys);
method(Object,sorted, prim_sorted );
# undef method
_set(sym___globals__, Symbol,value, nil);

+ 23
- 14
test.ref Parādīt failu

@ -9,8 +9,8 @@ o = Object.new(foo:42, bar: 666) => <>
o.foo => 42
Point.new() => <<Point>>
Point.new(x: 3, y: 4) => <<Point>>
| y: 4
| x: 3
| y: 4
twice 21 is 42
double => <<Closure>>
| environment: nil
@ -27,28 +27,39 @@ double => <>
Point.new(x:3, y:4).magnitude() => 5.000000
<<?>>
| self: nil =>
| self: nil
| n: 39
| self: nil
| 0: 40
40
<<?>>
| self: nil =>
| self: nil
| n: 40
| self: nil
| 0: 40
41
<<?>>
| self: nil =>
| self: nil
| n: 41
| self: nil
| 0: 40
42
<<?>>
| self: nil =>
| self: nil
| n: 42
| self: nil
| 0: 40
43
<Object>
| __codeon__: <primitive Object.codeOn>
| __eval__: <primitive Object.__eval__>
| __name__: Object
| allKeys: <primitive Object.allKeys>
| keys: <primitive Object.keys>
| length: <primitive Object.length>
| new: <primitive Object.new>
| pop: <primitive Object.pop>
| push: <primitive Object.push>
| sorted: <primitive Object.sorted>
nil no
1 yes
hello yes
@ -70,8 +81,8 @@ nil
<Object>
nil
[KEY: __delegate__
KEY: y
KEY: x
KEY: y
]
Symbol
<Symbol>
@ -147,14 +158,13 @@ MACRO table <>
| | | body: <<Object>>
| | | | 0: <<Call>>
| | | | | arguments: <<Object>>
| | | | | | 0: MACRO EVAL test with
| | | | | | 0: "MACRO EVAL test with "
| | | | | | 1: <<GetVar>>
| | | | | | | name: x
| | | | | | 2: and
| | | | | | 2: " and "
| | | | | | 3: <<GetVar>>
| | | | | | | name: y
| | | | | | 4:
| | | | | | 4: "\n"
| | | | | function: <<GetVar>>
| | | | | | name: print
| | | | 1: <<Unyop>>
@ -163,13 +173,12 @@ MACRO table <>
| | | | | | body: <<Object>>
| | | | | | | 0: <<Call>>
| | | | | | | | arguments: <<Object>>
| | | | | | | | | 0: REPLACEMENT
| | | | | | | | | 0: "REPLACEMENT "
| | | | | | | | | 1: <<Unyop>>
| | | | | | | | | | operation: 4
| | | | | | | | | | 0: <<GetVar>>
| | | | | | | | | | | name: x
| | | | | | | | | 2:
| | | | | | | | | 2: "\n"
| | | | | | | | function: <<GetVar>>
| | | | | | | | | name: print
| | | | | | | 1: <<Unyop>>
@ -193,7 +202,7 @@ AST eval => 42
65 66 67 68 69
1 two 3 four
test.txt:346: *: illegal operand types Integer and String
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)

+ 4
- 2
test.txt Parādīt failu

@ -79,6 +79,8 @@ print(counter(), "\n");
print(counter(), "\n");
print(counter(), "\n");
print(Object, full:1, "\n");
test(x) { print(x, " "); if (x) print("yes\n") else print("no\n") }
test(nil);
@ -225,7 +227,7 @@ nil.__delegate__.__delegate__.__delegate__.println();
Object.dump()
{
print("[");
keys = self.keys();
keys = self.allKeys().sorted();
for (key in keys) print("KEY: ", key, "\n");
print("]\n");
}
@ -254,7 +256,7 @@ print("P.mag ", p.magnitude(), "\n");
o = [bar:666, 1, [2, 3, 6*7], foo:42];
print(o, "\n", full:1);
print(o, "\n", full: 1);
o.dump();

Notiek ielāde…
Atcelt
Saglabāt