ometa Ada <: Parser
{
	fromTo :x :y = seq(x) (~seq(y) char)* seq(y),
	space        = super(#space) | fromTo('--', '\n') | fromTo('/*', '*/'),
	nameFirst    = '_' | '$' | letter,
	nameRest     = nameFirst | digit,
	tsName       = firstAndRest(#nameFirst, #nameRest):xs -> xs.join('').toLowerCase(),
	name         = spaces tsName,
	kwd :k       = spaces seq(k),
	SC           = spaces (';' | {print("Semicolon missing")}),
	number       = digit+:ws ('.' digit+ | empty -> []):fs -> parseFloat(ws.join('')+'.'+ fs.join('')),
	escapeChar   = '\\' char:c  -> unescape('\\' + c),
	str          = seq('"""')  (escapeChar | ~seq('"""') char)*:cs seq('"""') -> cs.join('')
               | '\'' (escapeChar | ~'\'' char)*:cs '\''                      -> cs.join('')
               | '"'  (escapeChar | ~'"'  char)*:cs '"'                       -> cs.join(''),

	PROGRAM = (WITH | USE)* PROC:p -> p
,	WITH = kwd('with') QNAME SC
,	USE  = kwd('use')  QNAME SC
,	QNAME= name '.' QNAME | name 
,	PROC = kwd('procedure') name:tBeg kwd('is')
	         DECL:decl
	       kwd('begin')
	         BODY:body
	       kwd('end') name:tEnd SC
	       (?(tBeg == tEnd) | {print("Warning! Mismatching names: "+tBeg+" and "+tEnd+".")})
		-> function(){
			var env = decl()
			body(env)
		}
,	DECL = VARDECL*:vd
		-> function(){
			var env = {"put_line": print}
			for(var i=0; i<vd.length; ++i)
				vd[i](env)
			return env
		}
,	VARDECL = name:vn spaces ':' name:tn spaces seq(':=') EXPR:e SC
		-> function(env){
			env[vn] = e(env)
		}

,	BODY = STATEMENT*:sc
		-> function(env){
			for(var i=0; i<sc.length; ++i)
				sc[i](env)
		}
,	STATEMENT = PROC_CALL
,	PROC_CALL = name:f spaces '(' EXPR:e spaces ')' SC
		-> function(env) {
			var ff = env[f]
			env[f](e(env))
		}
,	EXPR = SIMPLE_E:f -> f
,	SIMPLE_E = spaces name:v
		-> function(env){
			return env[v]
		}
	  | spaces str:s
		-> function(env){
			return s
		}
}