1+ const { rule, either, exactly, optional, minOf, token } = require ( './rule-helpers' ) ;
2+
3+ // LineStatement -> IfExpressionStatement | AssignmentStatement | FunctionStatement
4+ const LineStatement = rule (
5+ ( ) => either ( IfExpressionStatement , AssignmentStatement , FunctionStatement ) ,
6+ expression => expression
7+ ) ;
8+
9+ // IfExpressionStatement -> IfKeyword PStart Expression PEnd CodeBlock
10+ const IfExpressionStatement = rule (
11+ ( ) => exactly ( IfKeyword , PStart , Expression , PEnd , CodeBlock ) ,
12+ ( [ , , check , , statements ] ) => ( { type : 'if' , check, statements } )
13+ )
14+
15+ // CodeBlock -> BStart LineStatement* BEnd
16+ const CodeBlock = rule (
17+ ( ) => exactly ( BStart , minOf ( 0 , LineStatement ) , BEnd ) ,
18+ ( [ , statements ] ) => statements
19+ ) ;
20+
21+ // FunctionStatement -> FunctionExpression Eol
22+ const FunctionStatement = rule (
23+ ( ) => exactly ( FunctionExpression , Eol ) ,
24+ ( [ expression ] ) => expression
25+ ) ;
26+
27+ // FunctionExpression -> Name PStart FunctionParameters? PEnd
28+ const FunctionExpression = rule (
29+ ( ) => exactly ( Name , PStart , optional ( FunctionParameters , [ ] ) , PEnd ) ,
30+ ( [ name , _ , parameters ] ) => ( {
31+ type : 'function' ,
32+ name : name . value ,
33+ parameters
34+ } )
35+ ) ;
36+
37+ // FunctionParameters -> Expression (Comma Expression)*
38+ const FunctionParameters = rule (
39+ ( ) => exactly ( Expression , minOf ( 0 , exactly ( Comma , Expression ) ) ) ,
40+ ( [ first , rest ] ) => [ first , ...rest . map ( ( [ _ , parameter ] ) => parameter ) ]
41+ ) ;
42+
43+ // AssignmentStatement -> Name Equals Expression Eol
44+ const AssignmentStatement = rule (
45+ ( ) => exactly ( Name , Equals , Expression , Eol ) ,
46+ ( [ name , , expression ] ) => ( { type : 'assignment' , name : name . value , expression } )
47+ ) ;
48+
49+ // We use this functions for all binary operations in the
50+ // Expression rule because all of them parse the same way
51+ // this will allow us to create nested operations.
52+ const processBinaryResult = ( [ left , right ] ) => {
53+ let expression = left ;
54+
55+ // We need to go through all operators on the right side
56+ // because there can be 3 or more operators in an expression.
57+ for ( const [ operator , rightSide ] of right ) {
58+
59+ // Each time we encounter an expression we put the
60+ // previous one in the left side.
61+ expression = {
62+ type : 'operation' ,
63+ operation : operator . value ,
64+ left : expression ,
65+ right : rightSide
66+ } ;
67+ }
68+
69+ // Finally we return the expression structure.
70+ return expression ;
71+ } ;
72+
73+ // Expression -> EqualityTerm ((And | Or) EqualityTerm)*
74+ const Expression = rule (
75+ ( ) => exactly ( EqualityTerm , minOf ( 0 , exactly ( either ( And , Or ) , EqualityTerm ) ) ) ,
76+ processBinaryResult
77+ ) ;
78+
79+ // EqualityTerm -> RelationTerm ((DoubleEquals | NotEquals) RelationTerm)*
80+ const EqualityTerm = rule (
81+ ( ) => exactly ( RelationTerm , minOf ( 0 , exactly ( either ( DoubleEquals , NotEquals ) , RelationTerm ) ) ) ,
82+ processBinaryResult
83+ ) ;
84+
85+ // EqualityTerm -> AddSubTerm ((Less | Greater | LessEquals | GreaterEquals) AddSubTerm)*
86+ const RelationTerm = rule (
87+ ( ) => exactly ( AddSubTerm , minOf ( 0 , exactly ( either ( Less , Greater , LessEquals , GreaterEquals ) , AddSubTerm ) ) ) ,
88+ processBinaryResult
89+ ) ;
90+
91+ // AddSubTerm -> MulDivTerm ((Add | Subtract) MulDivTerm)*
92+ const AddSubTerm = rule (
93+ ( ) => exactly ( MulDivTerm , minOf ( 0 , exactly ( either ( Add , Subtract ) , MulDivTerm ) ) ) ,
94+ processBinaryResult
95+ ) ;
96+
97+ // MulDivTerm -> UnaryTerm ((Multiply | Divide) UnaryTerm)*
98+ const MulDivTerm = rule (
99+ ( ) => exactly ( UnaryTerm , minOf ( 0 , exactly ( either ( Multiply , Divide ) , UnaryTerm ) ) ) ,
100+ processBinaryResult
101+ ) ;
102+
103+ // UnaryTerm -> Not? Factor
104+ const UnaryTerm = rule (
105+ ( ) => exactly ( optional ( Not ) , Factor ) ,
106+ ( [ addedNot , value ] ) => ( {
107+ type : 'unary' ,
108+ withNot : addedNot . type !== 'optional' ,
109+ value
110+ } )
111+ ) ;
112+
113+ // Factor -> GroupExpression | FunctionExpression | NumberExpression | VariableExpression | StringExpression
114+ const Factor = rule (
115+ ( ) => either ( GroupExpression , FunctionExpression , NumberExpression , VariableExpression , StringExpression ) ,
116+ factor => factor
117+ ) ;
118+
119+ // GroupExpression -> PStart Expression PEnd
120+ const GroupExpression = rule (
121+ ( ) => exactly ( PStart , Expression , PEnd ) ,
122+ ( [ , expression ] ) => expression
123+ ) ;
124+
125+ // VariableExpression -> Name
126+ const VariableExpression = rule (
127+ ( ) => Name ,
128+ name => ( {
129+ type : 'variable' ,
130+ name : name . value
131+ } )
132+ ) ;
133+
134+ // NumberExpression -> Number
135+ const NumberExpression = rule (
136+ ( ) => Number ,
137+ number => ( {
138+ type : 'number' ,
139+ value : number . value
140+ } )
141+ ) ;
142+
143+ // StringExpression -> String
144+ const StringExpression = rule (
145+ ( ) => String ,
146+ string => ( {
147+ type : 'string' ,
148+ value : string . value
149+ } )
150+ ) ;
151+
152+ // Tokens
153+ const Number = token ( 'number' ) ;
154+ const String = token ( 'string' ) ;
155+ const Name = token ( 'name' ) ;
156+ const Equals = token ( 'operator' , '=' ) ;
157+ const PStart = token ( 'parenStart' ) ;
158+ const PEnd = token ( 'parenEnd' ) ;
159+ const BStart = token ( 'codeBlockStart' ) ;
160+ const BEnd = token ( 'codeBlockEnd' ) ;
161+ const Comma = token ( 'comma' ) ;
162+ const Eol = token ( 'endOfLine' ) ;
163+ const IfKeyword = token ( 'keyword' , 'if' ) ;
164+ const And = token ( 'operator' , '&&' ) ;
165+ const Or = token ( 'operator' , '||' ) ;
166+ const DoubleEquals = token ( 'operator' , '==' ) ;
167+ const NotEquals = token ( 'operator' , '!=' ) ;
168+ const Less = token ( 'operator' , '<' ) ;
169+ const Greater = token ( 'operator' , '>' ) ;
170+ const LessEquals = token ( 'operator' , '<=' ) ;
171+ const GreaterEquals = token ( 'operator' , '>=' ) ;
172+ const Add = token ( 'operator' , '+' ) ;
173+ const Subtract = token ( 'operator' , '-' ) ;
174+ const Multiply = token ( 'operator' , '*' ) ;
175+ const Divide = token ( 'operator' , '/' ) ;
176+ const Not = token ( 'operator' , '!' ) ;
177+
178+ module . exports = LineStatement ;
0 commit comments