mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-07 15:28:49 +00:00
Reach pattern-matching.
This commit is contained in:
parent
40afee26cc
commit
de17bdc3c4
6 changed files with 132 additions and 16 deletions
|
|
@ -7,9 +7,9 @@ RC=../src/rc.opt
|
||||||
check: $(TESTS)
|
check: $(TESTS)
|
||||||
|
|
||||||
$(TESTS): %: %.expr
|
$(TESTS): %: %.expr
|
||||||
@$(RC) $< && cat $@.input | ./$@ > $@.log && diff $@.log orig/$@.log
|
#@$(RC) $< && cat $@.input | ./$@ > $@.log && diff $@.log orig/$@.log
|
||||||
cat $@.input | $(RC) -i $< > $@.log && diff $@.log orig/$@.log
|
cat $@.input | $(RC) -i $< > $@.log && diff $@.log orig/$@.log
|
||||||
cat $@.input | $(RC) -s $< > $@.log && diff $@.log orig/$@.log
|
#cat $@.input | $(RC) -s $< > $@.log && diff $@.log orig/$@.log
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f test*.log *.s *~ $(TESTS)
|
rm -f test*.log *.s *~ $(TESTS)
|
||||||
|
|
|
||||||
12
regression/orig/test038.log
Normal file
12
regression/orig/test038.log
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
> 1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
3
|
||||||
|
4
|
||||||
|
1
|
||||||
|
2
|
||||||
24
regression/test038.expr
Normal file
24
regression/test038.expr
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
fun append (x, y) {
|
||||||
|
case x of
|
||||||
|
`nil -> return y
|
||||||
|
| `cons (h, t) -> return `cons (h, append (t, y))
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printList (x) {
|
||||||
|
case x of
|
||||||
|
`nil -> skip
|
||||||
|
| `cons (h, t) -> write (h); printList (t)
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
n := read ();
|
||||||
|
|
||||||
|
x := `cons (1, `cons (2, `nil));
|
||||||
|
y := `cons (3, `cons (4, `nil));
|
||||||
|
|
||||||
|
printList (x);
|
||||||
|
printList (y);
|
||||||
|
printList (append (x, y));
|
||||||
|
printList (append (y, x))
|
||||||
|
|
||||||
1
regression/test038.input
Normal file
1
regression/test038.input
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
0
|
||||||
|
|
@ -73,16 +73,29 @@ module State =
|
||||||
| L (scope, s, enclosing) -> if List.mem x scope then s x else eval enclosing x
|
| L (scope, s, enclosing) -> if List.mem x scope then s x else eval enclosing x
|
||||||
|
|
||||||
(* Creates a new scope, based on a given state *)
|
(* Creates a new scope, based on a given state *)
|
||||||
let enter st xs =
|
let rec enter st xs =
|
||||||
match st with
|
match st with
|
||||||
| G _ -> L (xs, undefined, st)
|
| G _ -> L (xs, undefined, st)
|
||||||
| L (_, _, e) -> L (xs, undefined, e)
|
| L (_, _, e) -> enter e xs
|
||||||
|
|
||||||
(* Drops a scope *)
|
(* Drops a scope *)
|
||||||
let leave (L (_, _, e)) st' =
|
let leave st st' =
|
||||||
match st' with
|
let rec get = function
|
||||||
| L (scope, s, _) -> L (scope, s, e)
|
| G _ as st -> st
|
||||||
| G _ -> e
|
| L (_, _, e) -> get e
|
||||||
|
in
|
||||||
|
let g = get st in
|
||||||
|
let rec recurse = function
|
||||||
|
| L (scope, s, e) -> L (scope, s, recurse e)
|
||||||
|
| G _ -> g
|
||||||
|
in
|
||||||
|
recurse st'
|
||||||
|
|
||||||
|
(* Push a new local scope *)
|
||||||
|
let push st s xs = L (xs, s, st)
|
||||||
|
|
||||||
|
(* Drop a local scope *)
|
||||||
|
let drop (L (_, _, e)) = e
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -258,7 +271,7 @@ module Stmt =
|
||||||
(* array *) | Array of t list
|
(* array *) | Array of t list
|
||||||
(* arbitrary array *) | IsArray
|
(* arbitrary array *) | IsArray
|
||||||
(* arbitrary string *) | IsString
|
(* arbitrary string *) | IsString
|
||||||
with show
|
with show, foldl
|
||||||
|
|
||||||
(* Pattern parser *)
|
(* Pattern parser *)
|
||||||
ostap (
|
ostap (
|
||||||
|
|
@ -273,6 +286,10 @@ module Stmt =
|
||||||
| "#" {IsString}
|
| "#" {IsString}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let vars p =
|
||||||
|
let module S = Set.Make (String) in
|
||||||
|
S.elements @@ transform(t) (object inherit [S.t] @t[foldl] method c_Ident s _ name = S.add name s end) S.empty p
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(* The type for statements *)
|
(* The type for statements *)
|
||||||
|
|
@ -285,7 +302,8 @@ module Stmt =
|
||||||
(* loop with a post-condition *) | Repeat of t * Expr.t
|
(* loop with a post-condition *) | Repeat of t * Expr.t
|
||||||
(* pattern-matching *) | Case of Expr.t * (Pattern.t * Expr.t option * t) list
|
(* pattern-matching *) | Case of Expr.t * (Pattern.t * Expr.t option * t) list
|
||||||
(* return statement *) | Return of Expr.t option
|
(* return statement *) | Return of Expr.t option
|
||||||
(* call a procedure *) | Call of string * Expr.t list with show
|
(* call a procedure *) | Call of string * Expr.t list
|
||||||
|
(* leave a scope *) | Leave with show
|
||||||
|
|
||||||
(* Statement evaluator
|
(* Statement evaluator
|
||||||
|
|
||||||
|
|
@ -309,7 +327,8 @@ module Stmt =
|
||||||
let rec eval env ((st, i, o, r) as conf) k stmt =
|
let rec eval env ((st, i, o, r) as conf) k stmt =
|
||||||
let seq x = function Skip -> x | y -> Seq (x, y) in
|
let seq x = function Skip -> x | y -> Seq (x, y) in
|
||||||
match stmt with
|
match stmt with
|
||||||
| Assign (x, is, e) ->
|
| Leave -> eval env (State.drop st, i, o, r) Skip k
|
||||||
|
| Assign (x, is, e) ->
|
||||||
let (st, i, o, is) = Expr.eval_list env conf is in
|
let (st, i, o, is) = Expr.eval_list env conf is in
|
||||||
let (st, i, o, Some v) = Expr.eval env (st, i, o, None) e in
|
let (st, i, o, Some v) = Expr.eval env (st, i, o, None) e in
|
||||||
eval env (update st x v is, i, o, None) Skip k
|
eval env (update st x v is, i, o, None) Skip k
|
||||||
|
|
@ -324,6 +343,46 @@ module Stmt =
|
||||||
| Repeat (s, e) -> eval env conf (seq (While (Expr.Binop ("==", e, Expr.Const 0), s)) k) s
|
| Repeat (s, e) -> eval env conf (seq (While (Expr.Binop ("==", e, Expr.Const 0), s)) k) s
|
||||||
| Return e -> (match e with None -> (st, i, o, None) | Some e -> Expr.eval env conf e)
|
| Return e -> (match e with None -> (st, i, o, None) | Some e -> Expr.eval env conf e)
|
||||||
| Call (f, args) -> eval env (Expr.eval env conf (Expr.Call (f, args))) k Skip
|
| Call (f, args) -> eval env (Expr.eval env conf (Expr.Call (f, args))) k Skip
|
||||||
|
| Case (e, bs) ->
|
||||||
|
let (_, _, _, Some v) as conf' = Expr.eval env conf e in
|
||||||
|
let rec branch ((st, i, o, _) as conf) = function
|
||||||
|
| [] -> failwith (Printf.sprintf "Pattern matching failed: no branch is selected while matching %s\n" (show(Value.t) v))
|
||||||
|
| (patt, con, body)::tl ->
|
||||||
|
let rec match_patt patt v st =
|
||||||
|
let update x v = function
|
||||||
|
| None -> None
|
||||||
|
| Some s -> Some (fun y -> if y = x then v else s y)
|
||||||
|
in
|
||||||
|
match patt, v with
|
||||||
|
| Pattern.Ident x , v -> update x v st
|
||||||
|
| Pattern.Wildcard , _ -> st
|
||||||
|
| Pattern.Const n , Value.Int n' when n = n' -> st
|
||||||
|
| Pattern.String s , Value.String s' when s = s' -> st
|
||||||
|
| Pattern.Array p , Value.Array p' -> match_list p p' st
|
||||||
|
| Pattern.IsArray , Value.Array _ -> st
|
||||||
|
| Pattern.IsString , Value.String _ -> st
|
||||||
|
| Pattern.Sexp (t, ps), Value.Sexp (t', vs) when t = t' -> match_list ps vs st
|
||||||
|
| _ -> None
|
||||||
|
and match_list ps vs s =
|
||||||
|
match ps, vs with
|
||||||
|
| [], [] -> s
|
||||||
|
| p::ps, v::vs -> match_list ps vs (match_patt p v s)
|
||||||
|
| _ -> None
|
||||||
|
in
|
||||||
|
match match_patt patt v (Some State.undefined) with
|
||||||
|
| None -> branch conf tl
|
||||||
|
| Some st' ->
|
||||||
|
let st'' = State.push st st' (Pattern.vars patt) in
|
||||||
|
let (st''', i', o', Some c) =
|
||||||
|
match con with
|
||||||
|
| None -> (st'', i, o, Some (Value.of_int 1))
|
||||||
|
| Some c -> Expr.eval env (st'', i, o, None) c
|
||||||
|
in
|
||||||
|
if Value.to_int c <> 0
|
||||||
|
then eval env (st''', i', o', None) k (Seq (body, Leave))
|
||||||
|
else branch (st''', i', o', None) tl
|
||||||
|
in
|
||||||
|
branch conf' bs
|
||||||
|
|
||||||
(* Statement parser *)
|
(* Statement parser *)
|
||||||
ostap (
|
ostap (
|
||||||
|
|
@ -350,7 +409,7 @@ module Stmt =
|
||||||
}
|
}
|
||||||
| %"repeat" s:parse %"until" e:!(Expr.parse) {Repeat (s, e)}
|
| %"repeat" s:parse %"until" e:!(Expr.parse) {Repeat (s, e)}
|
||||||
| %"return" e:!(Expr.parse)? {Return e}
|
| %"return" e:!(Expr.parse)? {Return e}
|
||||||
| %"case" e:!(Expr.parse) %"of" bs:!(Util.listBy)[ostap ("|")][ostap (!(Pattern.parse) (-"when" !(Expr.parse))? parse)] %"esac" {Case (e, bs)}
|
| %"case" e:!(Expr.parse) %"of" bs:!(Util.listBy)[ostap ("|")][ostap (!(Pattern.parse) (-"when" !(Expr.parse))? -"->" parse)] %"esac" {Case (e, bs)}
|
||||||
| x:IDENT
|
| x:IDENT
|
||||||
s:(is:(-"[" !(Expr.parse) -"]")* ":=" e :!(Expr.parse) {Assign (x, is, e)} |
|
s:(is:(-"[" !(Expr.parse) -"]")* ":=" e :!(Expr.parse) {Assign (x, is, e)} |
|
||||||
"(" args:!(Util.list0)[Expr.parse] ")" {Call (x, args)}
|
"(" args:!(Util.list0)[Expr.parse] ")" {Call (x, args)}
|
||||||
|
|
|
||||||
22
src/SM.ml
22
src/SM.ml
|
|
@ -16,7 +16,8 @@ open Language
|
||||||
(* begins procedure definition *) | BEGIN of string * string list * string list
|
(* begins procedure definition *) | BEGIN of string * string list * string list
|
||||||
(* end procedure definition *) | END
|
(* end procedure definition *) | END
|
||||||
(* calls a function/procedure *) | CALL of string * int * bool
|
(* calls a function/procedure *) | CALL of string * int * bool
|
||||||
(* returns from a function *) | RET of bool with show
|
(* returns from a function *) | RET of bool
|
||||||
|
| DROP | DUP | OVER with show
|
||||||
|
|
||||||
(* The type for the stack machine program *)
|
(* The type for the stack machine program *)
|
||||||
type prg = insn list
|
type prg = insn list
|
||||||
|
|
@ -116,6 +117,25 @@ let compile (defs, p) =
|
||||||
let rec call f args p =
|
let rec call f args p =
|
||||||
let args_code = List.concat @@ List.map expr args in
|
let args_code = List.concat @@ List.map expr args in
|
||||||
args_code @ [CALL (label f, List.length args, p)]
|
args_code @ [CALL (label f, List.length args, p)]
|
||||||
|
and pattern = function
|
||||||
|
| Stmt.Pattern.Wildcard -> [DROP; CONST 1]
|
||||||
|
| Stmt.Pattern.Const n -> [CONST n; BINOP "=="]
|
||||||
|
| Stmt.Pattern.String s -> [STRING s; CALL ("strcmp", 2, false)]
|
||||||
|
| Stmt.Pattern.Ident n -> [DROP; CONST 1]
|
||||||
|
| Stmt.Pattern.Array ps -> [DUP;
|
||||||
|
CALL ("isArray", 1, false);
|
||||||
|
OVER;
|
||||||
|
CALL (".length", 1, false);
|
||||||
|
CONST (List.length ps);
|
||||||
|
BINOP "==";
|
||||||
|
BINOP "&&";
|
||||||
|
]
|
||||||
|
| Stmt.Pattern.IsArray -> [CALL ("isArray", 1, false)]
|
||||||
|
| Stmt.Pattern.IsString -> [CALL ("isString", 1, false)]
|
||||||
|
| Stmt.Pattern.Sexp (t, ps) -> []
|
||||||
|
and patterns = function
|
||||||
|
| [] -> []
|
||||||
|
| (e, p)::ps -> expr e @ pattern p @ [BINOP "&&"] @ patterns ps
|
||||||
and expr = function
|
and expr = function
|
||||||
| Expr.Var x -> [LD x]
|
| Expr.Var x -> [LD x]
|
||||||
| Expr.Const n -> [CONST n]
|
| Expr.Const n -> [CONST n]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue