module formals; import std.stdio; import std.string; import lqtypes; import stringtools; alias LqType[string] kwdict; bool is_rest_arg(string name) { return stringtools.ends_with(name, "..."); } bool is_delayed_arg(string name) { return stringtools.starts_with(name, "*"); } bool is_keyword(string name) { return stringtools.starts_with(name, ":"); } /* Simple class to hold a function signature. */ class FunSig { string[] args = []; string restarg = null; string[] keywords = []; } FunSig funsig_from_formals(string[] formals) { /* formals ::= ( * ? * ) */ FunSig funsig = new FunSig(); /* get keywords first */ while (formals.length > 0) { string last_elem = formals[formals.length-1]; if (is_keyword(last_elem)) { funsig.keywords ~= last_elem; /* order doesn't matter */ formals = formals[0..formals.length-1]; } else break; } /* check for rest arg */ if (formals.length > 0 && is_rest_arg(formals[formals.length-1])) { funsig.restarg = formals[formals.length-1]; formals = formals[0..formals.length-1]; } /* anything else should be regular args */ foreach(string s; formals) { if (is_keyword(s) || is_rest_arg(s)) throw new Exception("invalid formals"); funsig.args ~= s; } return funsig; } /* Given a list of (evaluated) arguments, extract the keywords that were used, and their values. */ kwdict parse_keywords(LqType[] items) { kwdict keywords; foreach(int i, LqType q; items) { if (q.type_indicator() == "keyword") { string name = (cast(LqKeyword)q).lq_repr(); /* if this is the last element in the list, or it's followed by another keyword, set the value to true */ if (i==items.length-1 || items[i+1].type_indicator() == "keyword") { //frame.funargs.add_keyword(name, LQ_TRUE()); keywords[name] = LQ_TRUE(); } else { LqType value = items[i+1]; //frame.funargs.add_keyword(name, value); keywords[name] = value; } } } return keywords; } unittest { writefln("unittest: formals"); string[] a = ["a", "b", "rest...", ":this", ":that"]; FunSig fs = funsig_from_formals(a); assert(fs.args == ["a", "b"], std.string.join(fs.args, ";")); assert(fs.restarg == "rest..."); assert(fs.keywords == [":that", ":this"]); }