Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 79 additions & 28 deletions src/Expr.lama
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
-- Expression evaluator

import List;
import State;
import World;

-- As association map which maps "\otimes" into "\oplus"
var ops = {
["+" , infix + ],
["-" , infix - ],
["*" , infix * ],
["/" , infix / ],
["%" , infix % ],
["==", infix ==],
["!=", infix !=],
["<" , infix < ],
["<=", infix <=],
[">" , infix > ],
[">=", infix >=],
["&&", infix &&],
["!!", infix !!]
};

var ops = {["+", infix +],
["-", infix -],
["*", infix *],
["/", infix /],
["%", infix %],
["==", infix ==],
["!=", infix !=],
["<", infix <],
["<=", infix <=],
[">", infix >],
[">=", infix >=],
["&&", infix &&],
["!!", infix !!]};
-- The evaluator for infix operators: takes an operator as a string
-- and two operand values, and returns the result
public fun evalOp (op, l, r) {
case assoc (ops, op) of
Some (f) -> f (l, r)
esac
case assoc(ops, op) of
Some(f) -> f(l, r)
esac
}

-- Evaluates an expression "expr" in a configuration "c".
-- A configuration is a pair of a state "s" and a world "w".
-- Returns a final configuration (if any)
Expand All @@ -48,7 +43,6 @@ public fun evalOp (op, l, r) {
-- Const (int) |
-- Binop (string, expr, expr) |
-- Ignore (expr)

-- Evaluates a list of expressions, properly threading a configurations.
-- Returns the final configuration and the list of values
fun evalList (c, exprs) {
Expand All @@ -63,14 +57,71 @@ fun evalList (c, exprs) {
esac
}

-- s <- [name,val] -- add
-- s(x) -- get
fun eval (c@[s, w], expr) {
failure ("evalExpr not implemented\n")
case expr of
Var(v) -> [c, s(v)]
| Skip -> [c, 0]
| Binop(op, expr1, expr2) ->
case evalList(c, {expr1, expr2}) of
[c, {left, right}] -> [c, evalOp(op, left, right)]
esac
| Const(i) -> [c, i]
| Assn(expr1, expr2) ->
case evalList(c, {expr1, expr2}) of
[c@[s, w], {Ref(left), right}] -> [[s <- [left, right], w], right]
esac| Seq(expr1, expr2) -> let [c, v] = eval(c, expr1) in eval(c, expr2)
| Read(v) ->
case readWorld(w) of
[r, w] -> [[s <- [v, r], w], 0]
esac
| Write(exp) ->
case eval(c, exp) of
[c@[s, w], new] -> [[s, writeWorld(new, w)], 0]
esac
| If(state, try, fls) ->
case eval(c, state) of
[c, v] -> if v then eval(c, try) else eval(c, fls) fi
esac
| While(state, body) ->
case eval(c, state) of
[c, 0] -> [c, 0]
| [c, _] -> let [c, _] = eval(c, body) in eval(c, While(state, body))
esac
| DoWhile(state, body) -> eval(c, Seq(body, While(state, body)))
| Ignore(body) -> [eval(c, body)[0], 0]
| Ref(vall) -> [c, Ref(vall)]
| _ -> [c, 0]
esac
}


-- expr = Var (string) |
-- Const (int) |
-- Binop (string, expr, expr)
-- Evaluates a program with a given input and returns an output
public fun evalExpr (input, expr) {
case eval ([emptyState, createWorld (input)], expr) of
[c, _] -> c.snd.getOutput
esac
case eval([emptyState, createWorld(input)], expr) of
[c, _] -> c.snd.getOutput
| Var(v) -> input(v)
| Const(i) -> i
| Binop(op, expr1, expr2) -> evalBinop(op, evalExpr(input, expr1), evalExpr(input, expr2))
esac
}

public fun evalBinop(op, expr1, expr2) {
case op of
"+" -> expr1 + expr2
| "-" -> expr1 - expr2
| "*" -> expr1 * expr2
| "/" -> expr1 / expr2
| "%" -> expr1 % expr2
| "<" -> expr1 < expr2
| ">" -> expr1 > expr2
| "<=" -> expr1 <= expr2
| ">=" -> expr1 >= expr2
| "==" -> expr1 == expr2
| "!=" -> expr1 != expr2
| "&&" -> expr1 && expr2
| "!!" -> expr1 !! expr2
esac
}
111 changes: 60 additions & 51 deletions src/Parser.lama
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
-- Parser

import Ostap;
import Lexer;
import List;
Expand All @@ -10,73 +9,83 @@ import Collection;

-- Signals an error; takes an error message and location info
fun error (msg, loc) {
failure ("%s at %d:%d\n", msg, loc.fst, loc.snd)
failure("%s at %d:%d\n", msg, loc.fst, loc.snd)
}

-- An attribute-processing functions
-- Attributes are:
-- Val --- a plain value (aka "rvalue")
-- Ref --- a reference to a mutable cell (aka "lvalue")
-- Void --- no value (aka "void"/"unit")

-- Checks if a plain value "val" can be used in the context described by
-- the attribute "atr".
fun assertValue (atr, v, loc) {
case atr of
Ref -> error ("reference expected", loc)
| Void -> Ignore (v)
| _ -> v
esac
case atr of
Ref -> error("reference expected", loc)
| Void -> Ignore(v)
| _ -> v
esac
}

fun assertVoid (atr, v, loc) {
case atr of
Void -> v
| Val -> error ("value expected", loc)
| _ -> error ("reference expected", loc)
esac
case atr of
Void -> v
| Val -> error("value expected", loc)
| _ -> error("reference expected", loc)
esac
}

-- A parser of "something" in brackets; l, r are left and right
-- brackets as parsers, p --- a parser of "something"
fun inbr (l, p, r) {
syntax (-l p -r)
syntax (-l p -r)
}

fun binop (op) {
[syntax (pos -s[op]), fun (l, loc, r) {
fun (a) {
assertValue (a, Binop (op, l (Val), r (Val)), loc)
}
}
]
[syntax (pos -s[op]), fun (l, loc, r) {fun (a) {assertValue(a, Binop(op, l(Val), r(Val)), loc)}}]
}

var primary = memo $ eta syntax (
-- decimal constant
loc=pos x=decimal {fun (a) {assertValue (a, Const (stringInt (x)), loc)}} |

-- identifier
x=lident {fun (a) {
case a of
Ref -> Ref (x)
| Void -> Ignore (Var (x))
| _ -> Var (x)
esac
}} |
$(failure ("the rest of primary parsing in not implemented\n"))),
basic = memo $ eta (expr ({[Right, {[s (":="),
fun (l, loc, r) {
fun (a) {assertValue (a, Assn (l (Ref), r (Val)), loc)}
}]}],
[Left , map (binop, {"!!"})],
[Left , map (binop, {"&&"})],
[Nona , map (binop, {"==", "!=", "<", ">", "<=", ">="})],
[Left , map (binop, {"+", "-"})],
[Left , map (binop, {"*", "/", "%"})]
},
primary)),
exp = memo $ eta syntax (basic | s1=basic s[";"] s2=exp {fun (a) {Seq (s1 (Void), s2 (a))}});

var primary = memo $ eta syntax (
-- decimal constant
loc=pos x=decimal {fun (a) {assertValue(a, Const(stringInt(x)), loc)}} |

-- identifier
x=lident {
fun (a) {
case a of
Ref -> Ref(x)
| Void -> Ignore(Var(x))
| _ -> Var(x)
esac
}
} |
inbr[s("("), exp, s(")")] |

kRead expres=inbr[s("("), lident, s(")")] {fun (a) {assertVoid(a, Read(expres), loc)}} |
kSkip {fun (a) {assertVoid(a, Skip, loc)}} |
kWrite expres=inbr[s("("), exp, s(")")] {fun (a) {assertVoid(a, Write(expres(Val)), loc)}} |
kIf expres=exp kThen s1=exp s2=ifRec {fun (a) {If(expres(Val), s1(a), s2(a))}} |
kThen {fun (a) {assertVoid(a, Skip, loc)}} |
kWhile expres=exp kDo s=exp kOd {fun (a) {assertVoid(a, While(expres(Val), s(Void)), loc)}} |
kDo s=exp kWhile expres=exp kOd {fun (a) {assertVoid(a, DoWhile(expres(Val), s(Void)), loc)}} |
kFor i0=exp s[","] cond=exp s[","] step=exp kDo body=exp kOd {
fun (a) {assertVoid(a, Seq(i0(Void), While(cond(Val), Seq(body(Void), step(Void)))), loc)}
}
),
basic = memo $ eta (
expr({[Right, {[s(":="), fun (l, loc, r) {fun (a) {assertValue(a, Assn(l(Ref), r(Val)), loc)}}]}],
[Left, map(binop, {"!!"})],
[Left, map(binop, {"&&"})],
[Nona, map(binop, {"==", "!=", "<", ">", "<=", ">="})],
[Left, map(binop, {"+", "-"})],
[Left, map(binop, {"*", "/", "%"})]}, primary)
),
exp = memo $ eta syntax (
basic |
s1=basic s[";"] s2=exp {fun (a) {Seq(s1(Void), s2(a))}}
),
ifRec = memo $ eta syntax (
kElif expres=exp kThen try=exp fls=ifRec {fun (a) {If(expres(Val), try(a), fls(a))}} |

kElse s2=exp kFi {fun (a) {s2(a)}} |

kFi {fun (a) {assertVoid(a, Skip, loc)}}
);
-- Public top-level parser
public parse = syntax (s=exp {s (Void)});
public parse = syntax (s=exp {s(Void)});
Loading