Created
June 5, 2019 09:36
-
-
Save elias551/2d58096890ba0dd8772f3b5a1668b9fd to your computer and use it in GitHub Desktop.
masala parser calculation sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { C, F, N, Streams } from '@masala/parser' | |
/* | |
Implementing general solution : | |
E -> T E' | |
E' -> + TE' | eps | |
T -> F T' | |
T' -> * FT' | eps | |
F -> DAY | ( E ) | |
E== expr | |
T == subExpr | |
E'== optPlusExpr | |
T' == optMultExpr | |
F == terminal | |
expr -> subExpr optPlusExpr' | |
optPlusExpr -> ( + then subExpr then F.lazy(optPlusExpr) ).opt() | |
subExpr -> terminal then optMultExpr | |
optMultExpr -> ( * then terminal then F.lazy(optMultExpr) ).opt() | |
F -> F.try( '(' then expr then ')' ).or(N.litteral) | |
*/ | |
const MULT = Symbol('MULT') | |
const PLUS = Symbol('PLUS') | |
function text() { | |
return F.not(anyOperation().or(C.charIn('()'))) | |
.rep() | |
.map(v => parseInt(v.join('').trim(), 10)) | |
} | |
function blank() { | |
return C.char(' ') | |
.rep() | |
.returns(' ') | |
} | |
function anyOperation() { | |
return C.string('*') | |
.returns(MULT) | |
.or(C.string('+').returns(PLUS)) | |
} | |
function andOperation() { | |
return C.string('*').returns(MULT) | |
} | |
function plusOperation() { | |
return C.string('+').returns(PLUS) | |
} | |
function parenthesis(par) { | |
return C.char(' ') | |
.optrep() | |
.drop() | |
.then(C.char(par)) | |
} | |
function parenthesisExpr() { | |
return parenthesis('(') | |
.then(blank().opt()) | |
.drop() | |
.then(F.lazy(expr)) | |
.then( | |
parenthesis(')') | |
.then(blank().opt()) | |
.drop() | |
) | |
} | |
function expr() { | |
return subExpr() | |
.then(optionalPlusExpr()) | |
.map(v => { | |
const left = v.at(0) as any | |
const right = v.at(1) as any | |
return left + right.orElse(0) | |
}) | |
} | |
function optionalPlusExpr() { | |
return plusExpr().opt() | |
} | |
function plusExpr() { | |
return plusOperation() | |
.drop() | |
.then(subExpr()) | |
.then(F.lazy(optionalPlusExpr)) | |
.map(v => { | |
const left = v.at(0) as any | |
const right = v.at(1) as any | |
return left + right.orElse(0) | |
}) | |
} | |
function subExpr() { | |
return terminal() | |
.then(optionalMultExpr()) | |
.map(v => { | |
const left = v.at(0) as any | |
const right = v.at(1) as any | |
return left * right.orElse(1) | |
}) | |
} | |
function optionalMultExpr() { | |
return multExpr().opt() | |
} | |
function multExpr() { | |
return andOperation() | |
.drop() | |
.then(terminal()) | |
.then(F.lazy(optionalMultExpr)) | |
.map(v => { | |
const left = v.at(0) as any | |
const right = v.at(1) as any | |
return left * right.orElse(1) | |
}) | |
} | |
function terminal() { | |
return F.try(parenthesisExpr()).or(text()) | |
} | |
function combinator() { | |
return expr().then(F.eos().drop()) | |
} | |
const input = '2 + 3 * ( ( 4 + 10) + ( 4) ) + 1 * -3' | |
const stream = Streams.ofString(input) | |
const parsing = combinator().parse(stream) | |
console.log(input + '=' + JSON.stringify(parsing.value, null, 2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment