forked from gb3h/ocaml-type-inference-in-ts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.ts
130 lines (127 loc) · 4.74 KB
/
parser.ts
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* tslint:disable:max-classes-per-file */
import { ANTLRInputStream, CommonTokenStream } from 'antlr4ts'
import {
ExprContext,
OcamlParser,
BinaryOpContext,
ConstantIntContext,
ConstantBoolContext,
ConstantStrContext,
LetExprContext,
PatternContext,
Value_nameContext,
ValueNameContext,
ExprInParanthesesContext,
ConditionalExprContext,
WhileLoopContext,
ForLoopContext,
LambdaContext,
ParameterContext,
ApplicationContext,
GlobalLetExprContext,
LetRecExprContext,
GlobalLetRecExprContext,
} from '../lang/OcamlParser'
import { OcamlLexer } from '../lang/OcamlLexer'
import { OcamlVisitor } from '../lang/OcamlVisitor'
import { ParseTree } from 'antlr4ts/tree/ParseTree'
import { RuleNode } from 'antlr4ts/tree/RuleNode'
import { ErrorNode } from 'antlr4ts/tree/ErrorNode'
import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'
import { Apply, AstNode, basicType, BinaryOp, Conditional, For, GlobalLet, GlobalLetrec, Id, Lambda, Let, Letrec, Sequence, While } from '../type-inference/nodes'
import { ParseError } from '../type-inference/errors'
class ExpressionGenerator extends AbstractParseTreeVisitor<AstNode> implements OcamlVisitor<AstNode> {
visitValueName(ctx: ValueNameContext): Id {
return new Id(ctx.text, basicType.reference)
}
visitConstantInt(ctx: ConstantIntContext): AstNode {
return new Id(ctx.text, basicType.integer_literal)
}
visitConstantBool(ctx: ConstantBoolContext): AstNode {
return new Id(ctx.text, basicType.bool_literal)
}
visitConstantStr(ctx: ConstantStrContext): AstNode {
return new Id(ctx.text, basicType.string_literal)
}
visitExprInParantheses(ctx: ExprInParanthesesContext): AstNode {
return this.visit(ctx._inner)
}
visitBinaryOp(ctx: BinaryOpContext): AstNode {
return new BinaryOp(ctx._operator.text, this.visit(ctx._left), this.visit(ctx._right))
}
visitConditionalExpr(ctx: ConditionalExprContext): AstNode {
if (ctx._alternative) {
return new Conditional(this.visit(ctx._condition), this.visit(ctx._consequent), this.visit(ctx._alternative))
}
return new Conditional(this.visit(ctx._condition), this.visit(ctx._consequent))
}
visitWhileLoop(ctx: WhileLoopContext): AstNode {
return new While(this.visit(ctx._condition), this.visit(ctx._body))
}
visitForLoop(ctx: ForLoopContext): AstNode {
return new For(this.visitValue_Name(ctx._name), this.visit(ctx._binding), this.visit(ctx._end), this.visit(ctx._body))
}
visitLambda(ctx: LambdaContext): AstNode {
return new Lambda(ctx.parameter().map(param => this.visitParameter(param)), this.visit(ctx._body))
}
visitApplication(ctx: ApplicationContext): AstNode {
return new Apply(this.visit(ctx._fun), this.visit(ctx._argument))
}
visitParameter(ctx: ParameterContext): Id {
return this.visitPattern(ctx.pattern())
}
visitValue_Name(ctx: Value_nameContext): Id {
return new Id(ctx.text, basicType.reference)
}
visitPattern(ctx: PatternContext): Id {
return this.visitValue_Name(ctx._val);
}
visitLetExpr(ctx: LetExprContext): AstNode {
return new Let(this.visitPattern(ctx._name), this.visit(ctx._binding), this.visit(ctx._in_context))
}
visitGlobalLetExpr(ctx: GlobalLetExprContext): AstNode {
return new GlobalLet(this.visitPattern(ctx._name), this.visit(ctx._binding))
}
visitLetRecExpr(ctx: LetRecExprContext): AstNode {
return new Letrec(this.visitPattern(ctx._name), this.visit(ctx._binding), this.visit(ctx._in_context))
}
visitGlobalLetRecExpr(ctx: GlobalLetRecExprContext): AstNode {
return new GlobalLetrec(this.visitPattern(ctx._name), this.visit(ctx._binding))
}
defaultResult(): AstNode {
return new Id("Default", basicType.default)
}
visitExpr?: ((ctx: ExprContext) => AstNode) | undefined
visit(tree: ParseTree): AstNode {
return tree.accept(this)
}
visitChildren(node: RuleNode): AstNode {
const expressions: AstNode[] = []
for (let i = 0; i < node.childCount; i++) {
expressions.push(node.getChild(i).accept(this))
}
return new Sequence(expressions)
}
visitErrorNode(node: ErrorNode): AstNode {
throw new ParseError(node.toString() + " is not a valid expression")
}
}
function convertOcaml(expression: ExprContext): AstNode {
const generator = new ExpressionGenerator()
return expression.accept(generator)
}
export function parse(input: string) {
let program: AstNode | undefined
const inputStream = new ANTLRInputStream(input)
const lexer = new OcamlLexer(inputStream)
const tokenStream = new CommonTokenStream(lexer)
const parser = new OcamlParser(tokenStream)
parser.buildParseTree = true
try {
const tree = parser.expr()
program = convertOcaml(tree)
return program
} catch (error) {
throw error
}
}