Files
lci/lib/miniFun/Semantics.ml

353 lines
11 KiB
OCaml
Raw Normal View History

2024-10-25 21:29:49 +02:00
module Utility = Utility
open Types;;
Random.self_init ()
let (let*) = Result.bind
let rec evaluate (mem: memory) (command: t_exp) : (permittedValues, error) result =
match command with
Integer n -> Ok (IntegerPermitted n)
| Boolean b -> Ok (BooleanPermitted b)
| Variable v -> (
match VariableMap.find_opt v mem.assignments with
None -> Error (`AbsentAssignment ("The variable " ^ v ^ " is not defined."))
| Some a -> Ok a
)
| Function (xs, _, f) ->
Ok (FunctionPermitted
{inputList = xs;
body = f;
assignments = mem.assignments;
recursiveness = None}
)
| Application (f, xs) -> (
let* evalf = evaluate mem f in
let* funcClosure = (
match evalf with
FunctionPermitted ff -> Ok ff
| IntegerPermitted _ -> Error (`WrongType ("Function is not a function,"
^ " it's an integer"))
| BooleanPermitted _ -> Error (`WrongType ("Function is not a function,"
^ " it's a boolean"))
) in
let parmList = List.map (fun k -> evaluate mem k) xs in
let rec helper m params values =
match (params, values) with
(_, []) -> Ok (m, params)
| ([], _) ->
Error (`WrongArity ("Function application has arity " ^
(List.length funcClosure.inputList
|> string_of_int) ^
", but was applied to " ^
(List.length xs |> string_of_int) ^
" parameters"))
| (p::tlparams, (Ok v)::tlvalues) -> helper
(VariableMap.add p v m)
tlparams
tlvalues
| (_, (Error e)::_) -> Error e
in
let* (mem2assignments, params) = helper
funcClosure.assignments
funcClosure.inputList
parmList
2024-10-25 21:38:11 +02:00
in
let mem2 = (
match funcClosure.recursiveness with
None -> {assignments = mem2assignments}
| Some nameF -> {
assignments =
VariableMap.add
nameF
(FunctionPermitted funcClosure)
mem2assignments
}
) in
match params with
[] -> evaluate mem2 funcClosure.body
| _ -> (
Ok (FunctionPermitted {funcClosure with inputList = params;
assignments = mem2assignments}))
)
| Plus (a, b) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (aval + bval))
| Minus (a, b) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (aval - bval))
| Times (a, b) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (aval * bval))
| Division (a, b) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in (
try
Ok (IntegerPermitted (aval / bval))
with Division_by_zero -> Error (`DivisionByZero "Dividing by zero")
)
| Modulo (a, b) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (aval mod bval))
| Power (a, b) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (Utility.pow aval bval))
| PowerMod (a, b, c) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* bval = (
match evaluate mem b with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
let* cval = (
match evaluate mem c with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (Utility.powmod aval bval cval))
| Rand (a) ->
let* aval = (
match evaluate mem a with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
)
in
Ok (IntegerPermitted (Random.int aval))
| BAnd (a, b) ->
let* aval = (
match evaluate mem a with
Ok BooleanPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an boolean"))
)
in
let* bval = (
match evaluate mem b with
Ok BooleanPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an boolean"))
)
in
Ok (BooleanPermitted (aval && bval))
| BOr (a, b) ->
let* aval = (
match evaluate mem a with
Ok BooleanPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an boolean"))
)
in
let* bval = (
match evaluate mem b with
Ok BooleanPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an boolean"))
)
in
Ok (BooleanPermitted (aval || bval))
| BNot a ->
let* aval = (
match evaluate mem a with
Ok BooleanPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an boolean"))
)
in
Ok (BooleanPermitted (not aval))
| Cmp (exp_1, exp_2) ->
let* exp_1val = match evaluate mem exp_1 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
let* exp_2val = match evaluate mem exp_2 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
Ok (BooleanPermitted (exp_1val = exp_2val))
| CmpLess (exp_1, exp_2) -> (
let* exp_1val = match evaluate mem exp_1 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
let* exp_2val = match evaluate mem exp_2 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
Ok (BooleanPermitted (exp_1val < exp_2val))
)
| CmpLessEq (exp_1, exp_2) -> (
let* exp_1val = match evaluate mem exp_1 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
let* exp_2val = match evaluate mem exp_2 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
Ok (BooleanPermitted (exp_1val <= exp_2val))
)
| CmpGreater (exp_1, exp_2) -> (
let* exp_1val = match evaluate mem exp_1 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
let* exp_2val = match evaluate mem exp_2 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
Ok (BooleanPermitted (exp_1val > exp_2val))
)
| CmpGreaterEq (exp_1, exp_2) -> (
let* exp_1val = match evaluate mem exp_1 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
let* exp_2val = match evaluate mem exp_2 with
Ok IntegerPermitted x -> Ok x
| Error e -> Error e
| _ -> Error (`WrongType ("Value is not an integer"))
in
Ok (BooleanPermitted (exp_1val >= exp_2val))
)
| IfThenElse (guard, if_exp, else_exp) ->
let* bguard = (
match evaluate mem guard with
Ok BooleanPermitted b -> Ok b
| Error e -> Error e
| _ -> Error (`WrongType ("Value in if guard is not a boolean"))
) in
if bguard then
evaluate mem if_exp
else
evaluate mem else_exp
| LetIn (x, xval, rest) ->
let* evalxval = evaluate mem xval in
let mem2 = {assignments = VariableMap.add x evalxval mem.assignments} in
evaluate mem2 rest
| LetFun (f, xs, _, fbody, rest) ->
let mem2 = {
assignments =
VariableMap.add
f
(FunctionPermitted
{ inputList = xs;
body = fbody;
assignments = mem.assignments;
recursiveness = Some f})
mem.assignments}
in
evaluate mem2 rest
let reduce (program: t_exp) (iin : int) : (int, error) result =
let program' = (Application (program, [(Integer iin)])) in
let mem : memory = {assignments = VariableMap.empty} in
match (evaluate mem program') with
Ok IntegerPermitted a -> Ok a
| _ -> Error (`WrongType ("Main function doesn't return an integer"))