-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathSpine.g4
116 lines (106 loc) · 3.45 KB
/
Spine.g4
1
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
grammar Spine;
tokens { INDENT, DEDENT }
@lexer::members {
let CommonToken = require('antlr4/Token').CommonToken;
let SpineParser = require('./SpineParser').SpineParser;
SpineLexer.prototype.indents = [0];
SpineLexer.prototype.token_queue = [];
SpineLexer.prototype.nextToken = function() {
let next = antlr4.Lexer.prototype.nextToken.call(this);
return this.token_queue.length ? this.token_queue.shift() : next;
};
SpineLexer.prototype.pushToken = function(type, text) {
let stop = this.getCharIndex() - 1;
let start = text.length ? stop - text.length + 1 : stop;
let t = CommonToken(this._tokenFactorySourcePair, type, antlr4.Lexer.DEFAULT_TOKEN_CHANNEL, start, stop);
this.emitToken(t);
this.token_queue.push(t);
};
SpineLexer.prototype.previous = function() {
return this.indents[this.indents.length - 1];
};
}
COND : '?' ;
COND_ELSE : ':' ;
OR : 'or' ;
AND : 'and' ;
NOT : 'not' ;
EQ : '==' ;
NEQ : '!=' ;
GT : '>' ;
GE : '>=' ;
LT : '<' ;
LE : '<=' ;
PLUS : '+' ;
MINUS : '-' ;
MUL : '*' ;
DIV : '/' ;
MOD : '%' ;
COMMA : ',';
ARROW : '=>' ;
LPAR : '(' ;
RPAR : ')' ;
LSQBR : '[' ;
RSQBR : ']' ;
DEFINE : '=';
IF_COND : 'if' ;
IF_COND_ELSE : 'else' ;
ASSIGN : ':=' ;
FOR_STMT : 'for' ;
FOR_STMT_TO : 'to' ;
FOR_STMT_BY : 'by' ;
BREAK : 'break' ;
CONTINUE : 'continue' ;
INT_LITERAL : DIGITS ;
FLOAT_LITERAL : ( '.' DIGITS ( EXP )? | DIGITS ( '.' ( DIGITS ( EXP )? )? | EXP ) );
STR_LITERAL : ( '"' ( ESC | ~ ( '\\' | '\n' | '"' ) )* '"' | '\'' ( ESC | ~ ( '\\' | '\n' | '\'' ) )* '\'' );
BOOL_LITERAL : ( 'true' | 'false' );
COLOR_LITERAL : ( '#' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT | '#' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT );
ID : ( ID_LETTER ) ( ( '.' )? ( ID_BODY '.' )* ID_BODY )? ;
fragment ID_BODY : ( ID_LETTER | DIGIT )+ ;
fragment ID_LETTER : [a-zA-Z_] ;
fragment DIGIT : [0-9] ;
fragment ESC : '\\' . ;
fragment DIGITS : DIGIT+ ;
fragment HEX_DIGIT : [0-9a-fA-F] ;
fragment EXP : [eE] [+-]? DIGITS ;
fragment SPACES
: [ \t]+
;
COMMENT : '//' ~[\r\n]* -> skip;
WHITESPACE : [\n ] -> skip;
NEWLINE : (
( '\r'? '\n' | '\r' ) SPACES?
)
{
let spaces = this.text.replace(/[\r\n]+/g, '');
let indent = spaces.length;
if (indent > this.previous()) {
this.indents.push(indent);
this.pushToken(SpineParser.INDENT, spaces);
} else if (indent < this.previous()) {
while (this.previous() > indent) {
this.pushToken(SpineParser.DEDENT, "");
this.indents.pop();
}
} else {
// this.skip();
}
};
stmts: (call | decl | loop | branch | func)+;
block: INDENT stmts DEDENT;
args: (expr (COMMA expr)* (COMMA decl)*)? (decl (COMMA decl)*)?;
branch: IF_COND expr block (IF_COND_ELSE block)?;
call: ID LPAR args RPAR;
decl: ID ( DEFINE | ASSIGN ) ( expr | branch | tenary );
func: ID LPAR ID* RPAR ARROW block;
hist: ID LSQBR expr RSQBR;
loop: FOR_STMT decl FOR_STMT_TO expr ( FOR_STMT_BY INT_LITERAL )? loop_body;
loop_body: (expr | BREAK | CONTINUE)+;
tenary: expr COND expr COND_ELSE ( LPAR tenary RPAR | tenary | expr );
expr: ( MINUS? ( INT_LITERAL | FLOAT_LITERAL )| BOOL_LITERAL | STR_LITERAL | COLOR_LITERAL ) #Literal
| (NOT|MINUS)? call #Callexpr
| (NOT|MINUS)? ( hist | ID ) #Identifier
| LPAR ( tenary | expr ) RPAR #Group
| expr ( OR | AND | NOT | EQ | NEQ | GT | GE | LT | LE | PLUS | MINUS | MUL | DIV | MOD ) expr #Op
;