import { Terminal , Identifier } from './terminal' ; import { ILGen } from '../SDT/ILGen' ; import { LexicalScope } from '../SDT/LexicalScope' ; export class Expr { protected _rval : string ; constructor ( private op , protected left , protected right ) { } public print ( level = 0 ) { const pad = '' . padStart ( level * 2 ) ; console . log ( pad + this . op ) ; this . left && this . left . print ( level + 1 ) ; this . right && this . right . print ( level + 1 ) ; } public gen ( il , scope ) { if ( this . left && ( < Expr | Args > this . left ) . gen ) { ( < Expr | Args > this . left ) . gen ( il , scope ) ; } if ( this . right && ( < Expr | Args > this . right ) . gen ) { ( < Expr | Args > this . right ) . gen ( il , scope ) ; } const tempVar = scope . bindTempVar ( ) ; il . add ( `set ${ tempVar } ${ ( < Expr | Terminal > this . left ) . rvalue ( ) } ${ this . op } ${ ( < Expr | Terminal > this . right ) . rvalue ( ) }` ) ; this . _rval = tempVar ; } public rvalue ( ) { return this . _rval ; } public bindLexicalScope ( scope ) { if ( this . left && ( < Expr | Args > this . left ) . bindLexicalScope ) { ( < Expr | Args > this . left ) . bindLexicalScope ( scope ) ; } if ( this . right && ( < Expr | Args > this . right ) . bindLexicalScope ) { ( < Expr | Args > this . right ) . bindLexicalScope ( scope ) ; } } } export class FunctionCallExpr extends Expr { constructor ( private id , private args ) { super ( 'call' , id , args ) ; } gen ( il , scope ) { ( < Expr | Args > this . right ) . gen ( il , scope ) ; const tempVar = scope . bindTempVar ( ) ; il . add ( `call ${ scope . getLexemeName ( ( < Terminal > this . left ) . lvalue ( ) ) }` ) ; this . _rval = tempVar ; } } export class AssignExpr extends Expr { constructor ( private id , private expr ) { super ( '=' , id , expr ) ; } gen ( il , scope ) { il . add ( `declare ${ scope . getLexemeName ( this . id . lvalue ( ) ) }` ) ; ( < Expr > this . expr ) . gen ( il , scope ) ; il . add ( `${ scope . getLexemeName ( this . id . lvalue ( ) ) }=${ this . expr . rvalue ( ) }` ) ; } } export class Args { constructor ( private args , private type = 'call' ) { } print ( level ) { this . args . forEach ( x => { x . print ( level ) ; } ) ; } size ( ) { return this . args . length ; } bindLexicalScope ( scope ) { for ( let i = 0 ; i < this . args . length ; i ++ ) { if ( this . type === 'function' ) { scope . bind ( ( < Identifier > this . args [ i ] ) . value ) ; this . args [ i ] . bindLexicalScope ( scope ) ; } else { this . args [ i ] . bindLexicalScope && this . args [ i ] . bindLexicalScope ( scope ) ; } } } gen ( il , scope ) { if ( this . type == 'call' ) { for ( let i = 0 ; i < this . args . length ; i ++ ) { const expr = this . args [ i ] ; if ( ( < Expr > expr ) . gen ) { ( < Expr > expr ) . gen ( il , scope ) ; } il . add ( `pass ${ expr . rvalue ( ) }` ) ; } } } }