namespace M17N.Input
{
+ using Xex = System.Xml.Expression.Xexpression;
+
public class MInputMethod
{
// Delegaes
public static Callback GetSurroundingText;
public static Callback DeleteSurroundingText;
- internal static MExpression.Domain domain = new MExpression.Domain (null);
+ internal static Xex.Domain im_domain = new Xex.Domain (null);
private static MSymbol Minput_method = "input-method";
private static MSymbol Mdescription = "description";
private static MSymbol Mvariable = "variable";
}
}
- public class KeySeq : List<Key>
+ public class KeySeq : Xex.Object
{
- public KeySeq () : base () { }
+ List<Key> keyseq = new List<Key> ();
+
+ public KeySeq () { }
- public KeySeq (MPlist plist) : base ()
+ public KeySeq (MPlist plist)
{
foreach (MPlist p in plist)
{
if (p.IsSymbol)
- this.Add (new Key (p.Symbol));
+ keyseq.Add (new Key (p.Symbol));
else if (p.IsInteger)
- this.Add (new Key ((char) p.Integer));
+ keyseq.Add (new Key ((char) p.Integer));
else if (p.IsPlist)
- this.Add (new Key (p.Plist));
+ keyseq.Add (new Key (p.Plist));
else
throw new Exception ("Invalid Key Sequence: " + plist);
}
public KeySeq (MText mt) : base ()
{
for (int i = 0; i < mt.Length; i++)
- this.Add (new Key ((uint) mt[i]));
+ keyseq.Add (new Key ((uint) mt[i]));
}
private static uint parse_integer (string str)
return 0;
}
- public KeySeq (XmlNode node) : base ()
+ public KeySeq (XmlNode node)
{
XmlAttributeCollection acol = node.Attributes;
XmlNode n;
if (acol != null && (n = acol["keys"]) != null)
{
foreach (char c in n.Value)
- this.Add (new Key ((uint) c));
+ keyseq.Add (new Key ((uint) c));
}
for (node = node.FirstChild; node != null; node = node.NextSibling)
{
if (node.Name == "key-event")
- this.Add (new Key ((MSymbol) node.InnerText));
+ keyseq.Add (new Key ((MSymbol) node.InnerText));
else
- this.Add (new Key (parse_integer (node.InnerText)));
+ keyseq.Add (new Key (parse_integer (node.InnerText)));
+ }
+ }
+
+ public KeySeq (List<Xex.Term> list)
+ {
+ foreach (Xex.Term term in list)
+ {
+ if (term.IsName)
+ keyseq.Add (new Key ((MSymbol) term.Nameval.name));
+ else
+ keyseq.Add (new Key (term.Strval));
}
}
{
public MSymbol name;
public Dictionary<Key, Map> submaps;
- public MExpression actions;
+ public Xex actions;
- public void Add (KeySeq keys, int index, MExpression actions)
+ public void Add (KeySeq keys, int index, Xex actions)
{
Map sub = null;
this.actions = actions;
}
- public MExpression Lookup (KeySeq keys, int index)
+ public Xex Lookup (KeySeq keys, int index)
{
Map sub;
if (title != null)
mt.Cat (" \"" + title + "\"");
for (MPlist p = branches; ! p.IsEmpty; p = p.next)
- mt.Cat (" (" + p.Key + " " + (MExpression) p.Val + ")");
+ mt.Cat (" (" + p.Key + " " + (Xex) p.Val + ")");
return (string) mt + ")";
}
}
// Instance members
- internal MExpression.Domain local_domain;
+ internal Xex.Domain domain;
private LoadStatus load_status = LoadStatus.None;
private MDatabase.Tag tag;
private MText description;
internal MText title;
internal Command[] commands;
- internal Variable[] variables;
+ internal Xex.Name[] var_names;
internal Dictionary<MSymbol, Plugin> plugins;
- internal MPlist bindings;
internal Dictionary<MSymbol, Map> maps;
internal MPlist states;
static MInputMethod ()
{
- domain.Defun ("insert", insert, 1, 1);
- domain.Defun ("candidates", insert_candidates, 1, -1);
- domain.Defun ("delete", delete, 1, 1);
- domain.Defun ("select", select, 1, 1);
- domain.Defun ("show", show, 0, 0);
- domain.Defun ("hide", hide, 0, 0);
- domain.Defun ("move", move, 1, 1);
- domain.Defun ("mark", mark, 1, 1, true);
- domain.Defun ("pushback", pushback, 1, 1);
- domain.Defun ("pop", pop, 0, 0);
- domain.Defun ("undo", undo, 0, 1);
- domain.Defun ("commit", commit, 0, 0);
- domain.Defun ("unhandle", unhandle, 0, 0);
- domain.Defun ("shift", shift, 1, 1, true);
- domain.Defun ("call", call, 2, -1, true);
- // Pseudo functions to make arguments of special objects.
- domain.Defun ("marker", marker, 1, 1, true);
- domain.Defun ("char-at", char_at, 1, 1, true);
- domain.Defun ("keyseq", keyseq, 1, -1, true);
+ im_domain.DefSubr (Finsert, "insert", true, 1, 1);
+ im_domain.DefSubr (Finsert_candidates, "candidates", true, 1, -1);
+ im_domain.DefSubr (Fdelete, "delete", true, 1, 1);
+ im_domain.DefSubr (Fselect, "select", true, 1, 1);
+ im_domain.DefSubr (Fshow, "show", true, 0, 0);
+ im_domain.DefSubr (Fhide, "hide", true, 0, 0);
+ im_domain.DefSubr (Fmove, "move", true, 1, 1);
+ im_domain.DefSubr (Fmark, "mark", true, 1, 1);
+ im_domain.DefSubr (Fpushback, "pushback", true, 1, 1);
+ im_domain.DefSubr (Fpop, "pop", true, 0, 0);
+ im_domain.DefSubr (Fundo, "undo", true, 0, 1);
+ im_domain.DefSubr (Fcommit, "commit", true, 0, 0);
+ im_domain.DefSubr (Funhandle, "unhandle", true, 0, 0);
+ im_domain.DefSubr (Fshift, "shift", true, 1, 1);
+ im_domain.DefSubr (Fcall, "call", true, 2, -1);
+ im_domain.DefSubr (Fmarker, "marker", true, 1, 1);
+ im_domain.DefSubr (Fchar_at, "char-at", true, 1, 1);
+ im_domain.DefSubr (Fkeyseq, "keyseq", true, 1, -1);
MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
List<MDatabase> list = MDatabase.List (tag);
public MSymbol Name { get { return tag[2]; } }
public MSymbol SubName { get { return tag[3]; } }
- public bool Info (out MText description, out MText title,
- out Variable[] variables, out Command[] commands)
+ public bool Info (out MText description,
+ out MText title,
+ out Xex.Variable[] variables,
+ out Command[] commands)
{
if ((load_status & LoadStatus.Header) != LoadStatus.Header
&& ! load_header ())
}
description = this.description;
title = this.title;
- variables = this.variables;
+ variables = new Xex.Variable[var_names.Length];
+ int i = 0;
+ foreach (Xex.Name name in var_names)
+ variables[i++] = domain.GetVar (name);
commands = this.commands;
return true;
}
private bool load_body ()
{
- local_domain = new MExpression.Domain (domain, null);
+ domain = new Xex.Domain (domain, null);
mdb = MDatabase.Find (tag);
if (mdb == null)
return false;
State state = new State ((MSymbol) "init");
plist = new MPlist ();
foreach (KeyValuePair<MSymbol, Map>kv in maps)
- state.branches.Add (kv.Key, new MExpression (plist, local_domain));
+ state.branches.Add (kv.Key, new Xex (plist, domain));
states.Add (state.name, state);
}
}
State state = new State ((MSymbol) "init");
MPlist plist = new MPlist ();
foreach (KeyValuePair<MSymbol, Map>kv in maps)
- state.branches.Add (kv.Key, new MExpression (plist, local_domain));
+ state.branches.Add (kv.Key, new Xex (plist, domain));
states.Add (state.name, state);
}
}
return node.InnerText;
}
+ private void new_variable (Xex.Name name, string desc, int val,
+ MPlist pl, Xex.Variable vari)
+ {
+ Xex.Term term = new Xex.Term (val);
+ int[] range;
+
+ if (pl.IsEmpty)
+ range = null;
+ else
+ {
+ range = new int[pl.Count * 2];
+ for (int i = 0; i < range.Length; i++)
+ {
+ if (pl.IsPlist)
+ {
+ MPlist p = pl.Plist;
+
+ if (! p.IsInteger || ! p.next.IsInteger)
+ throw new Exception ("Invalid range: " + p);
+ range[i * 2] = p.Integer;
+ range[i * 2 + 1] = p.next.Integer;
+ }
+ else if (pl.IsInteger)
+ range[i * 2] = range[i * 2 + 1] = pl.Integer;
+ else
+ throw new Exception ("Invalid range: " + p);
+ }
+ }
+ if (vari == null)
+ domain.Defvar (new Xex.Variable.Int (name, desc, term, range));
+ else
+ {
+ vari.Value = term;
+ vari.DefaultValue = term;
+ vari.Range = range;
+ }
+ }
+
+ private void new_variable (Xex.Name name, string desc, MText val,
+ MPlist pl, Xex.Variable vari)
+ {
+ Xex.Term term = new Xex.Term ((string) val);
+ string[] range;
+
+ if (pl.IsEmpty)
+ range = null;
+ else
+ {
+ range = new string[pl.Count * 2];
+ for (int i = 0; i < range.Length; i++)
+ {
+ if (pl.IsMText)
+ range[i] = pl.Text;
+ else
+ throw new Exception ("Invalid range: " + p);
+ }
+ }
+ if (vari == null)
+ domain.Defvar (new Xex.Variable.Str (name, desc, term, range));
+ else
+ {
+ vari.Value = term;
+ vari.DefaultValue = term;
+ vari.Range = range;
+ }
+ }
+
+ private void new_variable (Xex.Name name, string desc, MSymbol val,
+ MPlist pl, Xex.Variable vari)
+ {
+ Xex.Term term = new Xex.Term ((Xex.Name) val.name);
+ Xex.Name[] range;
+
+ if (pl.IsEmpty)
+ range = null;
+ else
+ {
+ range = new Xex.Name[pl.Count * 2];
+ for (int i = 0; i < range.Length; i++)
+ {
+ if (pl.IsSymbol)
+ range[i] = pl.Symbol.name;
+ else
+ throw new Exception ("Invalid range: " + p);
+ }
+ }
+ if (vari == null)
+ domain.Defvar (new Xex.Variable.Sym (name, desc, term, range));
+ else
+ {
+ vari.Value = term;
+ vari.DefaultValue = term;
+ vari.Range = range;
+ }
+ }
+
private void parse_variables (MPlist plist)
{
variables = new Variable[plist.Count];
for (int i = 0; ! plist.IsEmpty; plist = plist.next)
if (plist.IsPlist && plist.Plist.IsSymbol)
- variables[i++] = new Variable (plist.Plist);
+ {
+ MPlist p = plist.Plist;
+ Xex.Name name = (Name) p.Symbol.name;
+ p = p.next;
+ string desc = parse_description (p);
+ Xex.Variable vari = null;
+ Xex.Term val;
+
+ if (im_global.domain.GetVar (name, out vari))
+ domain.Defvar (vari);
+ if (desc != null)
+ p = p.next;
+ if (! p.IsEmpty)
+ {
+ if (p.IsInteger)
+ new_variable (name, desc, p.Integer, p.next, vari);
+ else if (p.IsMText)
+ new_variable (name, desc, p.Text, p.next, vari);
+ else if (p.IsSymbol)
+ new_variable (name, desc, p.Symbol, p.next, vari);
+ else
+ throw new Exception ("Unknown type: " + p.val);
+ }
+ }
}
private void parse_variables (XmlNode node)
if (im == null || ! im.Open ())
continue;
if (id == MSymbol.nil)
- im.local_domain.CopyFunc (local_domain);
+ im.domain.CopyFunc (domain);
else
- im.local_domain.CopyFunc (local_domain, id);
+ im.domain.CopyFunc (domain, id);
}
for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
if (nn.NodeType == XmlNodeType.Element
&& nn.Name != "xi:include")
- local_domain.Defun ((MSymbol) node.GetAttribute ("id"));
+ domain.Defun ((MSymbol) node.GetAttribute ("id"));
for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
if (nn.NodeType == XmlNodeType.Element
&& nn.Name != "xi:include")
- local_domain.Defun ((MSymbol) node.GetAttribute ("id"), null,
+ domain.Defun ((MSymbol) node.GetAttribute ("id"), null,
nn.FirstChild);
}
if (target_type == Mmacro)
{
if (target_name == MSymbol.nil)
- im.local_domain.CopyFunc (local_domain);
+ im.domain.CopyFunc (domain);
else
- im.local_domain.CopyFunc (local_domain, target_name);
+ im.domain.CopyFunc (domain, target_name);
}
else if (target_type == Mmap)
{
if (! p.IsSymbol)
continue;
- local_domain.Defun (p.Symbol, null, null);
+ domain.Defun (p.Symbol, null, null);
}
for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
if (pl.IsPlist)
if (! p.IsSymbol)
continue;
transform (p.next);
- local_domain.Defun (p.Symbol, null, p.next);
+ domain.Defun (p.Symbol, null, p.next);
}
}
if (p.IsEmpty)
continue;
transform (p);
- MExpression expr = new MExpression (p, local_domain);
+ MXex expr = new MXex (p, domain);
map.Add (keys, 0, expr);
}
}
p = p.next;
transform (p);
state.branches.Add (map_name,
- new MExpression (p, local_domain));
+ new MXex (p, domain));
}
}
}
- private static object insert (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Finsert (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- ((MInputContext) domain.context).insert (args[0].Val);
-
- return true;
+ ((MInputContext) domain.context).insert (args[0]);
+ return args[0];
}
- private static object insert_candidates (MExpression[] args,
- MExpression.Domain domain)
+ private static Xex.Term Finsert_candidates (Xex.Domain domain,
+ Xex.Variable vari,
+ Xex.Term[] args)
{
- ((MInputContext) domain.context).insert_candidates ((MPlist) args[0].Val);
-
- return true;
+ ((MInputContext) domain.context).insert_candidates (args[0]);
+ return args[0];
}
- private static object marker (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fmarker (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
MSymbol sym = (MSymbol) args[0].Args[0].Val;
return ((MInputContext) domain.context).marker (sym);
}
- private static object char_at (MExpression[] args,
- MExpression.Domain domain)
+ private static Xex.Term char_at (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
return ((MInputContext) domain.context).char_at ((int) args[0].Val);
}
- private static object delete (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fdelete (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- ((MInputContext) domain.context).delete ((int) args[0].Val);
+ ((MInputContext) domain.context).delete ((int) args[0].Intval);
return true;
}
- private static object select (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
MInputContext ic = (MInputContext) domain.context;
- object val = args[0].Val;
- if (val is int)
- ic.select ((int) val);
+ if (args[0].IsInt)
+ ic.select (args[0].Intval);
else
- ic.select ((MSymbol) val);
- return true;
+ ic.select ((MSYmbol) ((string) args[0].Nameval));
+ return args[0];
}
- private static object show (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fshow (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
((MInputContext) domain.context).show ();
-
- return true;
+ return Xex.Zero;
}
- private static object hide (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fhide (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
((MInputContext) domain.context).hide ();
-
- return true;
+ return Xex.Zero;
}
- private static object move (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fmove (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- ((MInputContext) domain.context).move ((int) args[0].Val);
-
- return true;
+ ((MInputContext) domain.context).move (args[0].Intval);
+ return args[0];
}
- private static object mark (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fmark (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- MSymbol sym = (MSymbol) args[0].Val;
-
- ((MInputContext) domain.context).mark (sym);
- return true;
+ ((MInputContext) domain.context).mark (args[0]);
+ return args[0];
}
- private static object keyseq (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fkeyseq (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- MPlist p = new MPlist ();
-
- for (int i = 0; i < args.Length; i++)
- p.Add (MSymbol.symbol, (MSymbol) args[i].Val);
- return new KeySeq (p);
+ return new KeySeq (args[0].Listval);
}
- private static object pushback (MExpression[] args,
- MExpression.Domain domain)
+ private static Xex.Term Fpushback (Xex.Domain domain, Xex.Variable vari,
+ Xex[] args)
{
MInputContext ic = (MInputContext) domain.context;
- object val = args[0].Val;
-
- if (val is int)
- ic.pushback ((int) val);
- else if (val is MText)
- ic.pushback (new KeySeq ((MText) val));
- else if (val is KeySeq)
- ic.pushback ((KeySeq) val);
+
+ if (args[0].IsInt)
+ ic.pushback (args[0].Intval);
+ else if (args[0].IsStr)
+ ic.pushback (new KeySeq (args[0].Strval));
else
- throw new Exception ("Invalid keyseq: " + val);
- return true;
+ ic.pushback ((KeySeq) args[0].Objval);
+ return args[0];
}
- private static object pop (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fpop (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
((MInputContext) domain.context).pop ();
- return true;
+ return Xex.Zero;
}
- private static object undo (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fundo (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- int n = args.Length == 0 ? -2 : (int) args[0].Val;
+ int n = args.Length == 0 ? -2 : args[0].Intval;
((MInputContext) domain.context).undo (n);
- return true;
+ return Xex.Zero;
}
- private static object commit (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fcommit (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
((MInputContext) domain.context).commit ();
- return true;
+ return Xex.Zero;
}
- private static object unhandle (MExpression[] args,
- MExpression.Domain domain)
+ private static Xex.Term Funhandle (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
((MInputContext) domain.context).commit ();
- return false;
+ return Xex.Zero;
}
- private static object shift (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fshift (Xex.Domain domain, Xex.Variable vari,
+ Xex.Term[] args)
{
- MSymbol sym = (MSymbol) args[0].Args[0].Val;
-
- ((MInputContext) domain.context).shift (sym);
- return true;
+ ((MInputContext) domain.context).shift (args[0].Symval);
+ return args[0];
}
- private static object call (MExpression[] args, MExpression.Domain domain)
+ private static Xex.Term Fcall (Xex.Domain domain, Xex.Variable vari, Xex.Term[] args)
{
MSymbol module = (MSymbol) args[0].Args[0].Val;
MSymbol method = (MSymbol) args[1].Args[0].Val;
internal MText following_text = new MText ();
private bool key_unhandled;
- internal MExpression.Domain domain;
+ internal Xex.Domain domain;
public MInputContext (MInputMethod im)
{
this.im = im;
- domain = new MExpression.Domain (im.local_domain, this);
+ domain = new Xex.Domain (im.domain, this);
states = new Stack<MInputMethod.State> ();
states.Push ((MInputMethod.State) im.states.val);
keys = new MInputMethod.KeySeq ();
adjust_markers (from, to, mt);
}
- internal void insert (object arg)
+ internal void insert (Xex.Term arg)
{
- if (arg is int)
- preedit_replace (cursor_pos, cursor_pos, (int) arg);
+ if (arg.IsInt is int)
+ preedit_replace (cursor_pos, cursor_pos, arg.Intval);
else
- preedit_replace (cursor_pos, cursor_pos, (MText) arg);
+ preedit_replace (cursor_pos, cursor_pos, new MText (arg.Strval));
preedit_changed = true;
cursor_pos_changed = true;
}
group = new object[column];
}
+ public Candidates (List<Xex.Term> list, int column)
+ {
+ int nblocks = list.Count;
+
+ blocks = new Block[nblocks];
+ for (int i = 0, start = 0; i < nblocks; i++)
+ start += (blocks[i] = new Block (index, list[i])).Count;
+ if (column > 0)
+ group = new object[column];
+ }
+
public static void Detach (MInputContext ic)
{
ic.preedit.PopProp (0, ic.preedit.Length, MInputMethod.Mcandidates);
candidate_changed = true;
}
- internal void insert_candidates (MPlist list)
+ internal void insert_candidates (Xex.Term arg)
{
int column = 0;
if (val is int)
column = (int) val;
}
- candidates = new Candidates (list, column);
+ candidates = new Candidates (arg.Listval, column);
candidate_from = candidate_to = cursor_pos;
update_candidate ();
}
if (status == null)
status = im.title;
status_changed = true;
- MExpression on_entry
- = (MExpression) state.branches.Get (MSymbol.t);
+ Xex on_entry
+ = (Xex) state.branches.Get (MSymbol.t);
if (on_entry != null)
on_entry.Eval (domain);
}
if (! result)
return false;
if (! arglist.IsEmpty)
- (new MExpression (arglist, domain)).Eval (domain);
+ (new Xex (arglist, domain)).Eval (domain);
return true;
}
M17N_SRC = M17N.cs
CORE_SRC = MSymbol.cs MPlist.cs MCharTable.cs MText.cs MDatabase.cs
-EXPR_SRC = MExpression.cs
INPUT_SRC = MInputMethod.cs
XEX_SRC = XmlExpr.cs
-DLL = M17N.dll M17NCore.dll M17NExpr.dll M17NIM.dll XmlExpr.dll
+DLL = M17N.dll M17NCore.dll M17NIM.dll XmlExpr.dll
EXAMPLE = symbol.exe plist.exe chartab.exe text.exe textprop.exe database.exe \
- expr.exe
+ xex.exe
TEST = rearsticky.exe frontsticky.exe bothsticky.exe \
sensitive.exe frontsensitive.exe rearsensitive.exe
$(RUNCS) -out:$@ -t:library ${M17N_SRC}
M17NCore.dll: M17N.dll ${CORE_SRC}
- $(RUNCS) -out:$@ -t:library -r:M17N.dll -r:Mvp.Xml-bin-2.0/Mvp.Xml.dll ${CORE_SRC}
+ $(RUNCS) -out:$@ -t:library -r:M17N.dll ${CORE_SRC}
-M17NExpr.dll: M17N.dll M17NCore.dll ${EXPR_SRC}
- $(RUNCS) -out:$@ -t:library -r:M17N.dll -r:M17NCore.dll ${EXPR_SRC}
-
-M17NIM.dll: ${INPUT_SRC} M17N.dll M17NCore.dll M17NExpr.dll
- $(RUNCS) -out:$@ -t:library -r:M17N.dll -r:M17NCore.dll -r:M17NExpr.dll ${INPUT_SRC}
+M17NIM.dll: ${INPUT_SRC} M17N.dll M17NCore.dll XmlExpr.dll
+ $(RUNCS) -out:$@ -t:library -r:M17N.dll -r:M17NCore.dll -r:XmlExpr.dll ${INPUT_SRC}
XmlExpr.dll: ${XEX_SRC}
$(RUNCS) -out:$@ -t:library ${XEX_SRC}
-input.exe: input.cs ${DLL}
- $(RUNCS) -r:M17N.dll -r:M17NCore -r:M17NExpr -r:M17NIM.dll $<
+input.exe: input.cs M17NIM.dll
+ $(RUNCS) -r:M17N.dll -r:M17NCore -r:XmlExpr -r:M17NIM.dll $<
expr.exe: expr.cs
$(RUNCS) -r:M17N.dll -r:M17NCore -r:M17NExpr $<
{
private static NameTable nt = new NameTable ();
- private string name;
+ internal string name;
public Name (string str)
{
private static Name Ndescription = "description";
private static Name Nrange = "range";
- private static Name Nbreak = "break";
- private static Name Nreturn = "return";
-
internal abstract class Function
{
public Name name;
{
try {
if (args_evalled)
- domain.Catch (Nreturn);
+ domain.Catch (CatchTag.Return);
foreach (Term term in body)
{
result = term.Eval (domain);
public class Variable : Object
{
public readonly Name name;
+ public string desc;
+ internal Term default_val;
internal Term val;
+ object range;
- public Variable (Name name, Term term)
+ public Variable (Name name, Term value)
{
this.name = name;
- val = term;
+ val = value;
+ default_val = Zero;
+ }
+
+ public virtual bool ValueP (Term val) { return true; }
+
+ public Variable Clone ()
+ {
+ Variable v = new Variable (name, val);
+ v.desc = desc;
+ v.default_val = default_val;
+ v.range = range;
+ return v;
}
- public virtual Term Value
+ public Term Value
{
get { return val; }
- set
- {
- if (! ValueP (value))
- throw new Exception ("Invalid value of " + name + ": " + value);
- val = value;
- }
+ set {
+ if (! ValueP (value))
+ throw new Exception ("Invalid value: " + value);
+ val = value;
+ }
}
- public override Term Eval (Domain domain) { return val; }
+ public Term DefaultValue
+ {
+ get { return default_val; }
+ set {
+ if (! ValueP (value))
+ throw new Exception ("Invalid value: " + value);
+ default_val = value;
+ }
+ }
- public virtual bool ValueP (Term term) { return true; }
+ public virtual object Range
+ {
+ get { return range; }
+ set { range = value; }
+ }
+
+ public override Term Eval (Domain domain) { return val; }
public override string ToString () { return name + "(" + val + ")"; }
- internal class Int : Variable
+ public class Int : Variable
{
- public struct Range
- {
- public int from, to;
- }
+ public int[] range;
+
+ private static bool SubsetP (int[] r1, int[] r2)
+ {
+ if (r2 == null)
+ return true;
+ for (int i = 0; i < r1.Length; i += 2)
+ {
+ int j;
+ for (j = 0; j < r2.Length; j += 2)
+ if (r2[j] <= r1[i] && r2[j + 1] >= r1[i + 1])
+ break;
+ if (j >= r2.Length)
+ return false;
+ }
+ return true;
+ }
- public Range[] ranges;
+ private static bool SubsetP (int val, int[] r)
+ {
+ if (r == null)
+ return true;
+ for (int i = 0; i < r.Length; i += 2)
+ if (r[i] <= val && r[i + 1] >= val)
+ return true;
+ return false;
+ }
- public Int (Name name, int i) : base (name, new Term (i)) { }
+ public Int (Name name, string description, int value, int[] range)
+ : base (name, new Term (value))
+ {
+ if (! SubsetP (value, range))
+ throw new Exception ("Invalid value: " + value);
+ desc = description;
+ default_val = val;
+ this.range = range;
+ }
public override bool ValueP (Term term)
{
- int i;
-
- if (term.objval != null)
+ if (! term.IsInt)
return false;
- if (ranges == null)
- return true;
- i = term.intval;
- foreach (Range r in ranges)
- if (i >= r.from && i <= r.to)
- return true;
- return false;
+ return SubsetP (term.Intval, range);
+ }
+
+ public override object Range {
+ get { return range; }
+ set {
+ int[] r = (int[]) value;
+ if (! SubsetP (r, range)
+ || ! SubsetP (val.Intval, r)
+ || ! SubsetP (default_val.Intval, r))
+ throw new Exception ("Invalid range");
+ range = r;
+ }
}
}
internal class Str : Variable
{
- public string[] ranges;
+ public string[] range;
+
+ private static bool SubsetP (string[] r1, string[] r2)
+ {
+ foreach (string s in r1)
+ if (! SubsetP (s, r2))
+ return false;
+ return true;
+ }
+
+ private static bool SubsetP (string str, string[] r)
+ {
+ foreach (string s in r)
+ if (str == s)
+ return true;
+ return false;
+ }
- public Str (Name name, string str) : base (name, new Term (str)) { }
+ public Str (Name name, string description, string value, string[] range)
+ : base (name, new Term (value))
+ {
+ if (! SubsetP (value, range))
+ throw new Exception ("Invalid value: " + value);
+ desc = description;
+ default_val = val;
+ this.range = range;
+ }
public override bool ValueP (Term term)
{
if (! (term.objval is string))
return false;
- if (ranges == null)
+ return SubsetP (term.Strval, range);
+ }
+
+ public override object Range {
+ get { return range; }
+ set {
+ string[] r = (string[]) value;
+ if (! SubsetP (r, range)
+ || ! SubsetP (val.Strval, r)
+ || ! SubsetP (default_val.Strval, r))
+ throw new Exception ("Invalid range");
+ range = r;
+ }
+ }
+ }
+
+ internal class Sym : Variable
+ {
+ public Name[] range;
+
+ private static bool SubsetP (Name[] r1, Name[] r2)
+ {
+ foreach (Name n in r1)
+ if (! SubsetP (n, r2))
+ return false;
return true;
- string str = (string) term.objval;
- foreach (string s in ranges)
- if (s == str)
- return true;
- return false;
+ }
+
+ private static bool SubsetP (Name name, Name[] r)
+ {
+ foreach (Name n in r)
+ if (name == n)
+ return true;
+ return false;
+ }
+
+ public Sym (Name name, string description, Name value, Name[] range)
+ : base (name, new Term (value))
+ {
+ if (! SubsetP (value, range))
+ throw new Exception ("Invalid value: " + value);
+ desc = description;
+ default_val = val;
+ this.range = range;
+ }
+
+ public override bool ValueP (Term term)
+ {
+ if (! (term.objval is Name))
+ return false;
+ return SubsetP (term.Nameval, range);
+ }
+
+ public override object Range {
+ get { return range; }
+ set {
+ Name[] r = (Name[]) value;
+ if (! SubsetP (r, range)
+ || ! SubsetP (val.Nameval, r)
+ || ! SubsetP (default_val.Nameval, r))
+ throw new Exception ("Invalid range");
+ range = r;
+ }
}
}
}
}
#endif
+ internal class CatchTag : IEquatable<CatchTag>
+ {
+ private object val;
+
+ public CatchTag (Name name) { val = name.name; }
+ private CatchTag (int i) { val = i; }
+
+ public static CatchTag Return = new CatchTag (0);
+ public static CatchTag Break = new CatchTag (1);
+
+ public static bool operator== (CatchTag t1, CatchTag t2)
+ { return t1.val == t2.val; }
+
+ public static bool operator!= (CatchTag t1, CatchTag t2)
+ { return t1.val != t2.val; }
+
+ public bool Equals (CatchTag tag) { return this.val == tag.val; }
+ public override bool Equals (object val) { return this.val == val; }
+
+ public override int GetHashCode () { return val.GetHashCode (); }
+ }
+
public class Domain
{
public object context;
public int depth = 0;
internal Dictionary<Name, Function> functions;
+ internal Dictionary<Name, Dictionary<Name, Function>>
+ modules = new Dictionary<Name, Dictionary<Name, Function>> ();
internal Dictionary<Name, Variable> variables;
internal Bindings bindings;
- private Stack<Name> catch_stack = new Stack<Name> ();
+ private Stack<CatchTag> catch_stack = new Stack<CatchTag> ();
private int catch_count = 0;
internal Domain ()
bindings = bindings.UnboundTo (boundary);
}
- internal void Catch (Name name)
+ internal void Catch (CatchTag tag)
{
- catch_stack.Push (name);
+ catch_stack.Push (tag);
catch_count++;
}
internal void ThrowReturn ()
{
- foreach (Name tag in catch_stack)
+ foreach (CatchTag tag in catch_stack)
{
catch_count--;
- if (tag == Nreturn)
+ if (tag == CatchTag.Return)
break;
}
}
internal void ThrowBreak ()
{
- if (catch_stack.Peek () != Nbreak)
+ if (catch_stack.Peek () != CatchTag.Break)
throw new Exception ("No outer loop to break");
catch_count--;
}
+ internal void ThrowTag (CatchTag tag)
+ {
+ foreach (CatchTag elt in catch_stack)
+ {
+ catch_count--;
+ if (elt == tag)
+ break;
+ }
+ }
+
public void DefSubr (Builtin builtin, string str, bool setvar,
int min_arg, int max_arg, params string[] aliases)
{
return lambda;
}
- internal Function Defun (XmlNode node)
+ public void Defun (XmlNode node)
{
Name name = node.Attributes[Nfname].Value;
Function func;
if (! functions.TryGetValue (name, out func))
func = RegisterFunction (node);
((Function.Lambda) func).SetBody (node, this);
- return func;
}
public void Defvar (XmlNode node)
{
Name name = node.Attributes[0].Value;
+ String desc;
Variable vari;
node = node.FirstChild;
if (node.Name == Ndescription)
- node = node.NextSibling;
+ {
+ desc = node.InnerText;
+ node = node.NextSibling;
+ }
+ else
+ desc = null;
if (node != null)
{
Name type = node.Name;
if (type == Ninteger)
{
- Variable.Int vi = new Variable.Int (name, parse_integer (val));
+ int intval = parse_integer (val);
+ int[] range = null;
if (range_list != null)
{
- vi.ranges = new Variable.Int.Range[nranges];
-
+ range = new int[nranges * 2];
for (int i = 0; i < nranges; i++)
{
XmlNode n = range_list[i];
-
if (n.Name == Nrange)
{
- vi.ranges[i].from =
- parse_integer (n.FirstChild.InnerText);
- vi.ranges[i].to =
- parse_integer (n.LastChild.InnerText);
+ range[i * 2]
+ = parse_integer (n.FirstChild.InnerText);
+ range[i * 2 + 1]
+ = parse_integer (n.LastChild.InnerText);
}
else
{
- int num = parse_integer (n.InnerText);
- vi.ranges[i].from = vi.ranges[i].to = num;
+ range[i * 2]
+ = range[i * 2 + 1]
+ = parse_integer (n.InnerText);
}
}
}
- vari = vi;
+
+ if (variables.TryGetValue (name, out vari))
+ {
+ if (! (vari is Variable.Int))
+ throw new Exception ("Inalid value");
+ vari = vari.Clone ();
+ Term v = new Term (intval);
+ vari.Value = v;
+ vari.DefaultValue = v;
+ if (range != null)
+ vari.Range = range;
+ }
+ else
+ vari = new Variable.Int (name, desc, intval, range);
}
else if (type == Nstring)
{
- Variable.Str vs = new Variable.Str (name, val);
+ string[] range = null;
+ if (range_list != null)
+ {
+ range = new string[nranges];
+ for (int i = 0; i < nranges; i++)
+ range[i] = range_list[i].InnerText;
+ }
+
+ if (variables.TryGetValue (name, out vari))
+ {
+ if (! (vari is Variable.Str))
+ throw new Exception ("Invalid value");
+ vari = vari.Clone ();
+ Term v = new Term (val);
+ vari.Value = v;
+ vari.DefaultValue = v;
+ if (range != null)
+ vari.Range = range;
+ }
+ else
+ vari = new Variable.Str (name, desc, val, range);
+ }
+ else if (type == Nsymbol)
+ {
+ Name[] range = null;
if (range_list != null)
- vs.ranges = new string[nranges];
- for (int i = 0; i < nranges; i++)
- vs.ranges[i] = range_list[i].Value;
- vari = vs;
+ {
+ range = new Name[nranges];
+ for (int i = 0; i < nranges; i++)
+ range[i] = range_list[i].InnerText;
+ }
+
+ if (variables.TryGetValue (name, out vari))
+ {
+ if (! (vari is Variable.Sym))
+ throw new Exception ("Invalid value");
+ vari = vari.Clone ();
+ Term v = new Term (val);
+ vari.Value = v;
+ vari.DefaultValue = v;
+ if (range != null)
+ vari.Range = range;
+ }
+ else
+ vari = new Variable.Sym (name, desc, val, range);
}
else
throw new Exception ("Unknown type: " + type);
}
else
- vari = new Variable (name, Zero);
+ {
+ if (variables.TryGetValue (name, out vari))
+ vari = vari.Clone ();
+ else
+ vari = new Variable (name, Zero);
+ }
variables[name] = vari;
}
+ public void Defvar (Variable vari)
+ {
+ variables[vari.name] = vari;
+ }
+
internal Variable Defvar (Name name)
{
Variable vari = new Variable (name, Zero);
domain.functions[kv.Key] = kv.Value;
}
- internal Variable GetVar (Name name)
+ public Variable GetVar (Name name)
{
Variable vari;
basic.DefSpecial (Fforeach, "foreach", 2, -1);
basic.DefSpecial (Fquote, "quote", 1, 1);
basic.DefSpecial (Ftype, "type", 1, 1);
+ basic.DefSpecial (Fcatch, "catch", 2, 2);
+ basic.DefSpecial (Fthrow, "throw", 1, 2);
}
private static Term Fset (Domain domain, Variable vari, Term[] args)
{
Term result = Zero;
try {
- domain.Catch (Nbreak);
+ domain.Catch (CatchTag.Break);
while (! domain.Thrown)
foreach (Term arg in args)
{
{
Term result = Zero;
try {
- domain.Catch (Nbreak);
+ domain.Catch (CatchTag.Break);
while (! domain.Thrown && args[0].Eval (domain).IsTrue)
for (int i = 1; i < args.Length; i++)
{
Bindings current = domain.bindings;
try {
- domain.Catch (Nbreak);
+ domain.Catch (CatchTag.Break);
foreach (Term term in list)
{
domain.Bind (vari, term);
return TermTerm;
}
- public abstract class Object
+ private static Term Fcatch (Domain domain, Variable vari, Term[] args)
{
- public abstract Term Eval (Domain domain);
+ Term result = Zero;
+ try {
+ domain.Catch (new CatchTag (args[0].Nameval));
+ result = args[1].Eval (domain);
+ } finally {
+ domain.Uncatch ();
+ }
+ return result;
+ }
+
+ private static Term Fthrow (Domain domain, Variable vari, Term[] args)
+ {
+ domain.ThrowTag (new CatchTag (args[0].Nameval));
+ return (args.Length == 1 ? Zero : args[1]);
+ }
+
+ public class Object
+ {
+ public virtual Term Eval (Domain domain) { return new Term (this); }
}
private class Funcall : Object
internal Variable vari;
internal Term[] args;
- public Funcall (Function func, Variable vari, Term[] args)
- {
- this.func = func;
- this.vari = vari;
- this.args = args;
- }
+ public Funcall (XmlNode node, Domain domain)
+ {
+ vari = null;
+ Name name = node.Name;
+
+ if (name == Nfuncall)
+ name = node.Attributes[0].Value;
+ else if (node.Attributes[Nvname] != null)
+ vari = domain.GetVar (node.Attributes[Nvname].Value);
+ func = domain.GetFunc (name);
+ XmlNodeList nlist = node.ChildNodes;
+ int nargs = nlist.Count;
+
+ if (nargs < func.min_arg
+ || (func.max_arg >= 0 && nargs > func.max_arg))
+ throw new Exception ("Invalid number of arguments to: "
+ + name + " " + nargs);
+ args = new Term[nargs];
+ for (int i = 0; i < nlist.Count; i++)
+ args[i] = new Term (nlist[i], domain);
+ }
+
+ public Funcall (Domain domain, Name fname, Name vname, Term[] args)
+ {
+ func = domain.GetFunc (fname);
+ vari = domain.GetVar (vname);
+ this.args = args;
+ }
public override Term Eval (Domain domain)
{
public Term (Name name) { intval = 0; objval = name; }
public Term (string str) { intval = 0; objval = str; }
public Term (List<Term> list) { intval = 0; objval = list; }
- public Term (Term term) { intval = 0; objval = term; }
+ public Term (Term term) { intval = term.intval; objval = term.objval; }
public Term (Object obj) { intval = 0; objval = obj; }
public Term (XmlNode node, Domain domain)
objval = list;
}
else
- {
- Function func;
- Variable vari = null;
- Term[] args;
-
- if (name == Nfuncall)
- name = node.Attributes[0].Value;
- else if (node.Attributes[Nvname] != null)
- vari = domain.GetVar (node.Attributes[Nvname].Value);
- func = domain.GetFunc (name);
- XmlNodeList nlist = node.ChildNodes;
- int nargs = nlist.Count;
-
- if (nargs < func.min_arg
- || (func.max_arg >= 0 && nargs > func.max_arg))
- throw new Exception ("Invalid number of arguments to: "
- + name + " " + nargs);
- args = new Term[nargs];
- for (int i = 0; i < nlist.Count; i++)
- args[i] = new Term (nlist[i], domain);
- objval = new Funcall (func, vari, args);
- }
+ objval = new Funcall (node, domain);
}
}
+ public int Objval {
+ get {
+ if (objval == null)
+ throw new Exception ("term is an integer: " + this);
+ return objval;
+ }
+ }
+
public int Intval {
get {
if (objval != null)
}
}
+ public string Nameval {
+ get {
+ if (! IsName)
+ throw new Exception ("term is not symbol: " + this);
+ return (Name) objval;
+ }
+ }
+
public List<Term> Listval {
get {
if (! IsList)
public bool IsName { get { return (objval is Name); } }
public bool IsList { get { return (objval is List<Term>); } }
+ public bool IsType (Type type)
+ {
+ return (objval == null ? type == typeof (int)
+ : type == objval.GetType ());
+ }
+
public Term Eval (Domain domain)
{
if (objval == null || objval is Name || objval is string)
return new Term ((List<Term>) objval);
if (objval is Object)
return ((Object) objval).Eval (domain);
- if (objval is Variable)
- return ((Variable) objval).val;
- if (objval is Term)
- return (Term) objval;
throw new Exception ("invalid Term object: " + objval);
}
}
}
- static Term Zero = new Term (0);
- static Term One = new Term (1);
- static Term TermInt = new Term (Ninteger);
- static Term TermStr = new Term (Nstring);
- static Term TermName = new Term (Nsymbol);
- static Term TermList = new Term (Nlist);
- static Term TermTerm = new Term ((Name) "term");
+ static private Term Zero = new Term (0);
+ static private Term One = new Term (1);
+ static private Term TermInt = new Term (Ninteger);
+ static private Term TermStr = new Term (Nstring);
+ static private Term TermName = new Term (Nsymbol);
+ static private Term TermList = new Term (Nlist);
+ static private Term TermTerm = new Term ((Name) "term");
internal static int parse_integer (string str)
{
if (c == '?')
return str[1];
- if (c == '0' && str[1] == 'x')
+ if ((c == '0' || c == '#') && str[1] == 'x')
{
i = 0;
for (int idx = 2; idx < len; idx++)
private Term[] terms;
- public Xexpression (string url, Domain domain)
+ private void parse_terms (Domain domain, XmlNode node)
{
- XmlDocument doc = new XmlDocument (Name.Table);
- XmlNode node;
-
- using (XmlTextReader reader = new XmlTextReader (url, Name.Table))
- {
- do {
- reader.Read ();
- } while (reader.NodeType != XmlNodeType.None
- && (reader.NodeType != XmlNodeType.Element
- || reader.Name != Nexpr));
- if (reader.NodeType == XmlNodeType.None)
- throw new Exception ("Node <expr> not found");
- node = doc.ReadNode (reader);
- }
-
int nterms = 0;
- for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
+ for (XmlNode n = node; n != null; n = n.NextSibling)
if (n.NodeType == XmlNodeType.Element)
{
if (n.Name == Ndefun)
terms = new Term[nterms];
int i = 0;
- for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
+ for (XmlNode n = node; n != null; n = n.NextSibling)
if (n.NodeType == XmlNodeType.Element)
{
if (n.Name == Ndefun)
}
}
+ public Xexpression (Domain domain, XmlNode node)
+ {
+ parse_terms (domain, node);
+ }
+
+ public Xexpression (Domain domain, string url)
+ {
+ XmlDocument doc = new XmlDocument (Name.Table);
+ XmlNode node;
+
+ using (XmlTextReader reader = new XmlTextReader (url, Name.Table))
+ {
+ do {
+ reader.Read ();
+ } while (reader.NodeType != XmlNodeType.None
+ && (reader.NodeType != XmlNodeType.Element
+ || reader.Name != Nexpr));
+ if (reader.NodeType == XmlNodeType.None)
+ throw new Exception ("Node <expr> not found");
+ node = doc.ReadNode (reader);
+ }
+ parse_terms (domain, node.FirstChild);
+ }
+
public Term Eval (Domain domain)
{
Term result = Zero;
domain.depth = 0;
try {
- domain.Catch (Nreturn);
+ domain.Catch (CatchTag.Return);
foreach (Term term in terms)
{
result = term.Eval (domain);
using System.Collections.Generic;
using System.IO;
using System.Xml;
-using System.Xml.Expression;
+using Xex = System.Xml.Expression.Xexpression;
public class Test
{
- public static void Main()
+ public static void Main(params string[] args)
{
- Xexpression.Domain domain = new Xexpression.Domain (null);
- Xexpression xex = new Xexpression ("xex.xml", domain);
+ Xex.Domain domain = new Xex.Domain (null);
+ Xex xex = new Xex (domain, "xex.xml");
- Xexpression.debug_level = 10;
+ if (args.Length >= 2 && args[0] == "-d")
+ Xex.debug_level = int.Parse (args[1]);
Console.WriteLine (xex);
Console.WriteLine (xex.Eval (domain));
}
REST =
'<rest>' VAR '</rest>'
-DEFVAR = DEFVAR-INT DEFVAR-STR
+DEFVAR = DEFVAR-INT DEFVAR-STR DEFVAR-SYM
DEFVAR-INT =
'<defvar vname="' VNAME '">'
<possible-value> STR * </possible-value>
'</defvar>'
+DEFVAR-SYM =
+ '<defvar vname"' VNAME '">'
+ DESCRIPTION ?
+ SYMBOL ?
+ <possible-value> SYMBOL * </possible-value>
+ '</defvar>'
+
DESCRIPTION =
'<description>' [ TEXT | GETTEXT ] '</description>'
| 'lt' | 'le' | 'eq' | 'ge' | 'gt' | 'noteq'
| 'add' | 'sub' | 'mul' | 'div' | 'mod'
| 'logand' | 'logior' | 'logxor' | 'lsh'
- | 'append' | 'concat' | 'nth' | 'copy' | 'ins' | 'del'
+ | 'append' | 'concat' | 'length' | 'nth' | 'copy' | 'ins' | 'del'
| 'progn' | 'if' | 'when' | 'cond'
- | 'loop' | 'break' | 'while' | 'foreach'
+ | 'loop' | 'while' | 'foreach' | 'break' | 'return'
| 'quote' | 'eval' | 'type'
;; TERM has a value, and is evaluated to a TERM as below.
'<gt>' INTTERM INTTERM '</gt>'
'<append>' ANYTERM + '</append>'
'<concat>' [ INTTERM | STRTERM | LISTTERM ] + '</concat>'
+'<length>' [ STRTERM | LISTTERM ] '</length>'
'<nth>' INTTERM [ STRTERM | LISTTERM ] '</nth>'
'<copy>' LISTTERM '</nth>'
'<ins vname="' VNAME '">' INTTERM [ STRTERM | LISTTERM ] '</ins>'
'<loop>' TERM + '</loop>'
'<while>' TERM + '</while>'
'<foreach vname="' VNAME '">' TERM + '</foreach>'
+'<break>' ANYTERM ? '</break>'
+'<return>' ANYTERM ? '</return>'
'<quote>' TERM '</quote>'
'<eval>' TERM '</eval>'
'<type>' ANYTERM '</type>'
</defun>
<defun fname="looptest">
- <args><fixed vname="l"/></args>
- <foreach vname="term"><varref vname="l"/>
- <eval><varref vname="term"/></eval>
- </foreach>
+ <args-unevalled><fixed vname="l"/></args-unevalled>
+ <loop><loop>
+ <foreach vname="term"><varref vname="l"/>
+ <eval><varref vname="term"/></eval>
+ </foreach>
+ </loop></loop>
+ <symbol>looptest-finished</symbol>
</defun>
- <funcall fname="looptest">
- <list>
- <set vname="i"><integer>0</integer></set>
- <return><symbol>returned</symbol></return>
- <add vname="i"><integer>1</integer></add>
- <varref vname="i"/>
- </list>
- </funcall>
<set vname="x"><integer>10</integer></set>
<set vname="str"><string>ABC</string></set>
<append>
+ <catch><symbol>tag</symbol>
+ <funcall fname="looptest">
+ <list>
+ <set vname="i"><integer>0</integer></set>
+ <throw><symbol>tag</symbol><symbol>returned</symbol></throw>
+ <add vname="i"><integer>1</integer></add>
+ <varref vname="i"/>
+ </list>
+ </funcall>
+ </catch>
<funcall fname="factorial"><varref vname="x"/></funcall>
<ins vname="str"><integer>1</integer><string>123</string></ins>
<del vname="str"><integer>2</integer><integer>4</integer></del>
<quote><add><varref vname="x"/><integer>1</integer></add></quote>
</eval>
</eval>
+ <concat><integer>?a</integer><integer>?b</integer></concat>
+ <quote><add><varref vname="x"/><integer>1</integer></add></quote>
</append>
</expr>