22 BinOpNode , ConstNode , Ast , Token , ParserOptions , AstNode , OperatorsMap , OperationTypes ,
33 Operators , AssignNode , TokenTypes , SetSingleVarNode , GetSingleVarNode , FunctionCallNode ,
44 getTokenType , getTokenValue , isTokenTypeLiteral , getStartLine , getStartColumn , getEndColumn ,
5- getEndLine , findOperators , splitTokens , DotObjectAccessNode , BracketObjectAccessNode
5+ getEndLine , findOperators , splitTokens , DotObjectAccessNode , BracketObjectAccessNode , findTokenValueIndexes , findTokenValueIndex , FunctionDefNode
66} from '../common' ;
77
88export class InstructionLine {
@@ -33,36 +33,65 @@ export class Parser {
3333 * @param options parsing options. By default it will exclude comments and include LOC (Line of code)
3434 */
3535 parse ( allTokens : Token [ ] , options : ParserOptions = { includeComments : false , includeLoc : true } ) : Ast {
36+
37+ if ( ! allTokens || ! allTokens . length ) { return { } as Ast ; }
38+
39+ // get all instruction lines starting at first line
40+ const instructions = this . getBlock ( allTokens , 1 ) ;
41+
3642 const ast = {
3743 name : "undefined.jspy" ,
44+ funcs : [ ] ,
3845 body : [ ]
3946 } as Ast ;
4047
41- if ( ! allTokens || ! allTokens . length ) { return ast ; }
48+ this . instructionsToNodes ( instructions , ast ) ;
49+ return ast ;
50+ }
4251
43- // get all instruction lines starting at first line
44- const instructions = this . getBlock ( allTokens , 1 ) ;
52+ private instructionsToNodes ( instructions : InstructionLine [ ] , ast : Ast ) : void {
4553
4654 for ( let instruction of instructions ) {
47- let node : AstNode | null = null ;
4855
4956 if ( ! instruction . tokens . length ) {
5057 continue ;
5158 }
5259
5360 const assignTokens = splitTokens ( instruction . tokens , '=' ) ;
5461
55- if ( assignTokens . length > 1 ) {
56- const target = this . createNode ( assignTokens [ 0 ] ) ;
57- const source = this . createNode ( assignTokens [ 1 ] ) ;
58- node = new AssignNode ( target , source ) ;
62+ if ( getTokenValue ( instruction . tokens [ 0 ] ) === 'def' ) {
63+ const funcName = getTokenValue ( instruction . tokens [ 1 ] ) as string ;
64+ const paramsTokens = instruction . tokens . slice (
65+ instruction . tokens . findIndex ( tkns => getTokenValue ( tkns ) === '(' ) + 1 ,
66+ instruction . tokens . findIndex ( tkns => getTokenValue ( tkns ) === ')' )
67+ ) ;
68+
69+ const params = splitTokens ( paramsTokens , ',' ) . map ( t => getTokenValue ( t [ 0 ] ) as string ) ;
70+
71+ const endDefOfDef = findTokenValueIndex ( instruction . tokens , v => v === ':' ) ;
72+
73+ if ( endDefOfDef === - 1 ) {
74+ throw ( `Can't find : for def` )
75+ }
76+
77+ const instructionLines = this . getBlock ( instruction . tokens , getStartLine ( instruction . tokens [ endDefOfDef + 1 ] ) ) ;
78+ const funcAst = {
79+ body : [ ] as AstNode [ ] ,
80+ funcs : [ ] as AstNode [ ]
81+ } as Ast ;
82+ this . instructionsToNodes ( instructionLines , funcAst ) ;
83+
84+ ast . funcs . push ( new FunctionDefNode ( funcName , params , funcAst . body ) )
85+
86+ } else if ( assignTokens . length > 1 ) {
87+ const target = this . createExpressionNode ( assignTokens [ 0 ] ) ;
88+ const source = this . createExpressionNode ( assignTokens [ 1 ] ) ;
89+ ast . body . push ( new AssignNode ( target , source ) ) ;
5990 } else {
60- node = this . createNode ( instruction . tokens )
91+ ast . body . push ( this . createExpressionNode ( instruction . tokens ) )
6192 }
6293
63- ast . body . push ( node )
6494 }
65- return ast ;
6695 }
6796
6897 private getBlock ( tokens : Token [ ] , startLine : number ) : InstructionLine [ ] {
@@ -76,20 +105,29 @@ export class Parser {
76105 const sLine = getStartLine ( token ) ;
77106 const sColumn = getStartColumn ( token ) ;
78107 if ( sLine >= startLine ) {
79- // first line defines a minimum indent
80- if ( column === 0 ) { column = sColumn ; }
81108
82- if ( sLine !== currentLine ) {
109+ if ( currentLine !== sLine ) {
110+ currentLine = sLine ;
111+ }
112+
113+ if ( column === sColumn ) {
83114 currentLine = sLine ;
84115 lines . push ( line ) ;
85116 line = new InstructionLine ( ) ;
86117 }
87118
88119 line . tokens . push ( token ) ;
89120
121+ // first line defines a minimum indent
122+ if ( column === 0 ) {
123+ column = sColumn ;
124+ }
125+
90126 // stop looping through if line has less indent
91127 // it means the corrent block finished
92- if ( sColumn < column ) { break ; }
128+ if ( sColumn < column ) {
129+ break ;
130+ }
93131 }
94132 }
95133
@@ -100,11 +138,12 @@ export class Parser {
100138 return lines ;
101139 }
102140
103- private createNode ( tokens : Token [ ] , prevNode : AstNode | null = null ) : AstNode {
141+ private createExpressionNode ( tokens : Token [ ] , prevNode : AstNode | null = null ) : AstNode {
104142 if ( tokens . length === 0 ) {
105143 throw new Error ( `Token length can't be null.` )
106144 }
107145
146+ // const or variable
108147 if ( tokens . length === 1
109148 || ( tokens . length === 2 && getTokenValue ( tokens [ 1 ] ) === '?' )
110149 ) {
@@ -150,8 +189,8 @@ export class Parser {
150189 const leftSlice2 = slice ( tokens , opIndex + 1 , nextOpIndex ) ;
151190 const rightSlice2 = slice ( tokens , nextOpIndex + 1 , nextOpIndex2 || tokens . length ) ;
152191
153- const left2 = this . createNode ( leftSlice2 ) ;
154- const right2 = this . createNode ( rightSlice2 ) ;
192+ const left2 = this . createExpressionNode ( leftSlice2 ) ;
193+ const right2 = this . createExpressionNode ( rightSlice2 ) ;
155194 rightNode = new BinOpNode ( left2 , nextOp , right2 ) ;
156195
157196 i ++ ;
@@ -163,15 +202,15 @@ export class Parser {
163202 // add up result
164203 if ( prevNode === null ) {
165204 const leftSlice = slice ( tokens , 0 , opIndex ) ;
166- prevNode = this . createNode ( leftSlice ) ;
205+ prevNode = this . createExpressionNode ( leftSlice ) ;
167206 }
168207 prevNode = new BinOpNode ( prevNode , op , rightNode )
169208
170209 } else {
171210 const leftSlice = prevNode ? [ ] : slice ( tokens , 0 , opIndex ) ;
172211 const rightSlice = slice ( tokens , opIndex + 1 , nextOpIndex || tokens . length ) ;
173- const left = prevNode || this . createNode ( leftSlice , prevNode ) ;
174- const right = this . createNode ( rightSlice ) ;
212+ const left = prevNode || this . createExpressionNode ( leftSlice , prevNode ) ;
213+ const right = this . createExpressionNode ( rightSlice ) ;
175214 prevNode = new BinOpNode ( left , op , right ) ;
176215 }
177216 }
@@ -186,15 +225,15 @@ export class Parser {
186225 // create DotObjectAccessNode
187226 const subObjects = splitTokens ( tokens , '.' ) ;
188227 if ( subObjects . length > 1 ) {
189- return new DotObjectAccessNode ( subObjects . map ( tkns => this . createNode ( tkns ) ) ) ;
228+ return new DotObjectAccessNode ( subObjects . map ( tkns => this . createExpressionNode ( tkns ) ) ) ;
190229 }
191230
192231 // create function call node
193232 if ( tokens . length > 2 && getTokenValue ( tokens [ 1 ] ) === '(' ) {
194233 const name = getTokenValue ( tokens [ 0 ] ) as string ;
195234 const paramsTokensSlice = tokens . slice ( 2 , tokens . length - 1 ) ;
196235 const paramsTokens = splitTokens ( paramsTokensSlice , ',' )
197- const paramsNodes = paramsTokens . map ( tkns => this . createNode ( tkns ) ) ;
236+ const paramsNodes = paramsTokens . map ( tkns => this . createExpressionNode ( tkns ) ) ;
198237
199238 return new FunctionCallNode ( name , paramsNodes ) ;
200239 }
@@ -203,7 +242,7 @@ export class Parser {
203242 if ( tokens . length > 2 && getTokenValue ( tokens [ 1 ] ) === '[' ) {
204243 const name = getTokenValue ( tokens [ 0 ] ) as string ;
205244 const paramsTokensSlice = tokens . slice ( 2 , tokens . length - 1 ) ;
206- const paramsNodes = this . createNode ( paramsTokensSlice ) ;
245+ const paramsNodes = this . createExpressionNode ( paramsTokensSlice ) ;
207246 return new BracketObjectAccessNode ( name , paramsNodes ) ;
208247 }
209248
0 commit comments