import * as t from '../lexer/token' ; import { unescape } from '../util' ; export abstract class Node < T > { constructor ( public value , public row , public column ) { } get name ( ) { return this . constructor . name ; } } export type ValType < N extends Node < any > > = N extends Node < infer V > ? V : never ; export interface NodeConstructor < T , N extends Node < T > > { new ( value , row , column ) : N ; } export abstract class Literal < T > extends Node < string > { parsedValue : T ; abstract parse ( rep ) ; constructor ( value , row , column ) { super ( value , row , column ) ; this . parsedValue = this . parse ( value ) ; } } export class IntLit extends Literal < number > { parse ( rep ) { return parseInt ( rep , 10 ) ; } static from ( token ) { return new IntLit ( token . rep , token . row , token . column ) ; } } export class FloatLit extends Literal < number > { parse ( rep ) { return parseFloat ( rep ) ; } static from ( token ) { return new FloatLit ( token . rep , token . row , token . column ) ; } } export class CharLit extends Literal < string > { parse ( rep ) { return unescape ( rep . slice ( 1 , - 1 ) ) ; } static from ( token ) { return new CharLit ( token . rep , token . row , token . column ) ; } } export class StrLit extends Literal < string > { parse ( rep ) { return unescape ( rep . slice ( 1 , - 1 ) ) ; } static from ( token ) { return new StrLit ( token . rep , token . row , token . column ) ; } } export class BoolLit extends Literal < boolean > { parse ( rep ) { return rep === 'true' ; } static from ( token ) { return new BoolLit ( token . rep , token . row , token . column ) ; } } export class Ident extends Node < string > { } export abstract class Operator < T extends string > extends Node < T > { } export type UnaryOperandType = { right : Type < any > ; ret : Type < any > ; } ; export class UnaryOp extends Operator < '+' | '-' | '!' > { static isUnaryOp ( token ) { return token . is ( t . Operator ) && [ '+' , '-' , '!' ] . includes ( token . rep ) ; } getOperandTypes ( ) { const res = ( ty ) => ( { right : ty , ret : ty } ) ; switch ( this . value ) { case '+' : return [ res ( IntType . instance ) , res ( FloatType . instance ) ] ; case '-' : return [ res ( IntType . instance ) , res ( FloatType . instance ) ] ; case '!' : return [ res ( BoolType . instance ) ] ; } } } export type BinaryOperandType = { left : Type < any > ; right : Type < any > ; ret : Type < any > ; } ; export abstract class BinaryOp < T extends string > extends Operator < T > { abstract precedence : number ; static isBinaryOp ( token ) { return ( token . is ( t . Operator ) && [ '+' , '-' , '==' , '!=' , '<' , '<=' , '>' , '>=' , '|' , '^' , '*' , '/' , '%' , '&' , '||' , '&&' , ] . includes ( token . rep ) ) ; } abstract getOperandTypes ( left ) ; } const binaryOperand = ( ty , ret = ty ) => ( { left : ty , right : ty , ret : ret , } ) ; export class EqOp extends BinaryOp < '==' | '!=' > { precedence = 0 ; getOperandTypes ( left ) { return [ binaryOperand ( left , BoolType . instance ) ] ; } } export class CompOp extends BinaryOp < '<' | '<=' | '>' | '>=' > { precedence = 0 ; getOperandTypes ( left ) { return [ binaryOperand ( IntType . instance , BoolType . instance ) , binaryOperand ( FloatType . instance , BoolType . instance ) , binaryOperand ( BoolType . instance , BoolType . instance ) , binaryOperand ( CharType . instance , BoolType . instance ) , binaryOperand ( StrType . instance , BoolType . instance ) , ] ; } } export class AddOp extends BinaryOp < '+' | '-' | '|' | '^' > { precedence = 1 ; getOperandTypes ( left ) { switch ( this . value ) { case '+' : case '-' : return [ binaryOperand ( IntType . instance ) , binaryOperand ( FloatType . instance ) , ] ; case '|' : case '^' : return [ binaryOperand ( IntType . instance ) ] ; } } } export class MulOp extends BinaryOp < '*' | '/' | '%' | '&' > { precedence = 2 ; getOperandTypes ( left ) { switch ( this . value ) { case '*' : case '/' : return [ binaryOperand ( IntType . instance ) , binaryOperand ( FloatType . instance ) , ] ; case '%' : case '&' : return [ binaryOperand ( IntType . instance ) ] ; } } } export class BoolOp extends BinaryOp < '||' | '&&' > { precedence = 3 ; getOperandTypes ( left ) { return [ binaryOperand ( BoolType . instance ) ] ; } } export class Module extends Node < { imports : Array < Import > ; decls : Array < Decl > ; } > { } export class Import extends Node < { path : StrLit ; elems : Array < ImportElem > ; } > { } export type ImportElem = { name : Ident ; as : Ident | null ; } ; export class Decl extends Node < { name : Ident ; type : Type < any > | null ; expr : Expr < any > ; } > { } export class Assign extends Node < { lVal : LVal ; expr : Expr < any > ; } > { } export type LVal = IdentExpr | IndexExpr ; export class Break extends Node < null > { } export class Block extends Node < { bodies : Array < Expr < any > | Decl | Assign | Break > ; returnVoid : boolean ; } > { } export abstract class Expr < T > extends Node < T > { type : Type < any > | null = null ; } export class BinaryExpr extends Expr < { left : Expr < any > ; op : BinaryOp < any > ; right : Expr < any > ; } > { } export abstract class PrimUnaryExpr < T > extends Expr < T > { } export class UnaryExpr extends PrimUnaryExpr < { op : UnaryOp ; right : PrimUnaryExpr < any > ; } > { } export abstract class PrimExpr < T > extends PrimUnaryExpr < T > { } export class LitExpr extends PrimExpr < Literal < any > > { } export class IdentExpr extends PrimExpr < Ident > { } export type Tuple < T > = { size : number ; items : Array < T > ; } ; export class TupleExpr extends PrimExpr < Tuple < Expr < any > > > { } export class ArrayExpr extends PrimExpr < Array < Expr < any > > > { } export class CallExpr extends PrimExpr < { func : Expr < any > ; args : Expr < any > ; } > { } export class IndexExpr extends PrimExpr < { target : Expr < any > ; index : Expr < any > ; } > { } export class FuncExpr extends PrimExpr < { params : Tuple < Param > ; returnType : Type < any > ; body : Block ; } > { } export type Param = { name : Ident ; type : Type < any > ; } ; export class CondExpr extends PrimExpr < { if : Expr < any > ; then : Block ; else : Block ; } > { } export class LoopExpr extends PrimExpr < { while : Expr < any > ; body : Block ; } > { } export class NewExpr extends PrimExpr < { type : Type < any > ; length : Expr < any > ; } > { } export abstract class Type < T > extends Node < T > { constructor ( value , row , column ) { super ( value , row , column ) ; } } export abstract class SimpleType extends Type < null > { constructor ( row , column ) ; constructor ( value , row , column ) ; constructor ( ) { if ( arguments . length === 3 ) { super ( arguments [ 0 ] , arguments [ 1 ] , arguments [ 2 ] ) ; } else { super ( null , arguments [ 0 ] , arguments [ 1 ] ) ; } } } export abstract class PrimType extends SimpleType { } export class IntType extends PrimType { get name ( ) { return 'int' ; } static instance : IntType = new IntType ( - 1 , - 1 ) ; } export class FloatType extends PrimType { get name ( ) { return 'float' ; } static instance : FloatType = new FloatType ( - 1 , - 1 ) ; } export class StrType extends PrimType { get name ( ) { return 'str' ; } static instance : StrType = new StrType ( - 1 , - 1 ) ; } export class BoolType extends PrimType { get name ( ) { return 'bool' ; } static instance : BoolType = new BoolType ( - 1 , - 1 ) ; } export class CharType extends PrimType { get name ( ) { return 'char' ; } static instance : CharType = new CharType ( - 1 , - 1 ) ; } export class FuncType extends Type < { param : Type < any > ; return : Type < any > ; } > { get name ( ) { let paramName = this . value . param . name ; if ( this . value . param instanceof FuncType ) { paramName = `(${ paramName })` ; } return `${ paramName } -> ${ this . value . return . name }` ; } } export class TupleType extends Type < Tuple < Type < any > > > { get name ( ) { return `(${ this . value . items . map ( item => item . name ) . join ( ', ' ) })` ; } } export class ArrayType extends Type < Type < any > > { get name ( ) { return `[${ this . value . name }]` ; } } export class VoidType extends SimpleType { get name ( ) { return 'void' ; } static instance : VoidType = new VoidType ( - 1 , - 1 ) ; } export class AnyType extends SimpleType { static instance : AnyType = new AnyType ( - 1 , - 1 ) ; }