Plan 9 from Bell Labs’s /usr/web/sources/contrib/maht/inferno/appl/lib/mathmap.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


implement Mathmap;

include "sys.m";
	sys: Sys;
include "string.m";
	str : String;

include "bufio.m";
	bufio: Bufio;
	Iobuf: import bufio;

include "mathmap.m";


UserValue.arg_init(uservalue : self ref UserValue) : (string, string)
{
	init := "";
	arg := "uv_" + uservalue.name;
	pick uv := uservalue {
	Float or Int=>
		if(uv.min != "")
			init += arg + "->min(" + uv.min + ");\n";		
		if(uv.max != "")
			init += arg + "->max(" + uv.max + ");\n";		
		if(uv.default != "")
			init += arg + "->default(" + uv.default + ");\n";	
	Image =>
		if(uv.options != "")
			init += arg + "->options(" + uv.options + ");\n";		
	Bool or Color or Curve or Gradient =>
		;
	
	}
	return (arg, init);
}

in_list(ts : list of string, t : string) : int
{
	for(; ts != nil; ts = tl ts)
		if(hd ts == t)
			return 1;
	return 0;
}

Token.send(token : self ref Token, c : chan of ref Token) : ref Token
{
	# this also does transforms on the data type 
	pick t := token {
		Label =>
			case t.text {
			"xor" =>
				c <-= ref Token.Operator("xor");
			">" or "<" =>
				c <-= ref Token.Comparitor(t.text);
			"do" or "while" or "if" or "for" or "end" or "then"=>
				c <-= ref Token.Keyword(t.text);
			* =>
				(nil, tail) := str->toreal(t.text, 10);
				if(tail == "")
					c <- = ref Token.Number(t.text);
				else {
					if(in_list(functions, t.text)) {
						c <- = ref Token.Function(t.text);
					} else if(in_list(pre_defined_vars, t.text)) {
						c <- = ref Token.Predefvar(t.text);
					} else 
						c <-= token;
				}
			}
		* =>
			c <-= token;
	}
	return nil;
}

Token.unexpected(token : self ref Token, p : ref Parser) : string
{
	return " " + p.fname +":" + string p.line + " Unexepected " + token.text;
}

Parser.tokenizer(p : self ref Parser) {
	b := bufio->open(p.fname, Bufio->OREAD);
	c : int;
	token : ref Token;

	line := 0;

	token = nil;
	while(c = b.getc()) {
		case c  {
		'(' =>
			if(token != nil)
				token = token.send(p.tokens);
			p.tokens <-= ref Token.LeftCBracket("(");
		')' =>
			if(token != nil)
				token = token.send(p.tokens);
			p.tokens <-= ref Token.RightCBracket(")");
		'[' =>
			if(token != nil)
				token = token.send(p.tokens);
			p.tokens <-= ref Token.LeftSBracket("(");
		']' =>
			if(token != nil)
				token = token.send(p.tokens);
			p.tokens <-= ref Token.RightSBracket(")");
		':' =>
			if(token == nil)
				raise "Unexpected :";

			pick t := token {
				Label =>
					t.typetag = t.text;
				* =>
					raise "Unexpected :";
			}

		'+' or '-' or '*' or '/' or '%' or '^' or '!'=>
			if(token != nil)
				token = token.send(p.tokens);

			p.tokens <-= ref Token.Operator(sys->sprint("%c", c));
		'\n' =>
			p.line++;
			if(token != nil)
				token = token.send(p.tokens);
		' ' or '	' => 
			if(token != nil)
				token = token.send(p.tokens);
		',' =>
			if(token != nil)
				token = token.send(p.tokens);
			p.tokens <-= ref Token.Comma(",");
		'&' =>
			if(token != nil) {
				pick t := token {
					Operator =>
						if(t.text == "&") {
							t.text += "&";
						} else {
							raise "Unexpected &";
						}
					* =>
						token.send(p.tokens);
						token = ref Token.Operator("&");
				}
			} else {
				token = ref Token.Operator("&");
			}
		'=' =>
			if(token != nil) {
				pick t := token {
					Operator =>
						if(t.text == "=" || t.text == "<" || t.text == ">" || t.text == "!") {
							t.text += "=";
							token = ref Token.Comparitor(t.text);
							token = token.send(p.tokens);

						} else {
							raise "Unexpected =";
						}
					* =>
						token.send(p.tokens);
						token = ref Token.Operator("=");
				}
			} else {
				token = ref Token.Operator("=");
			}
		'|' =>
			if(token != nil) {
				pick t := token {
					Operator =>
						if(t.text == "|")
							t.text += "|";
						else
							raise "Unexpected |";
					* =>
						token.send(p.tokens);
						token = ref Token.Operator("|");
				}
			} else {
				token = ref Token.Operator("|");
			}
			
		* =>
			if(token == nil) {
				token = ref Token.Label(sys->sprint("%c", c), "");
			} else {
				pick t := token {
					Label =>
						t.text += sys->sprint("%c", c);
					* =>
						raise "Unexpected " + sys->sprint("%c", c);
				}
			}
		}
	}
}

Parser.label(p : self ref Parser) : string
{
	token := <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	tag := "";
	pick t := token {
		Label =>
			tag = t.text;
		* =>
			raise t.unexpected(p);
	}
	return tag;
}

Parser.label_typetag(p : self ref Parser) : string
{
	token := <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	tag := "";
	pick t := token {
		Label =>
			tag = t.typetag;
		* =>
			raise t.unexpected(p);
	}
	return tag;
}

Parser.number(p : self ref Parser) : string
{
	token := <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	num := "";
	pick t := token {
		Number =>
			num = t.text;
		Comma =>
			if(num == "")
				raise t.unexpected(p);
		* =>
			raise t.unexpected(p);
	}
	return num;
}

Parser.number_maybe(p : self ref Parser) : (int, string)
{
	token := <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	num := "";
	inargs := 1;
	pick t := token {
		Number =>
			num = t.text;
		RightCBracket =>
			inargs = 0;
		* =>
			raise t.unexpected(p);
	}
	return (inargs, num);
}

Parser.operator(p : self ref Parser) : string
{
	token := <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	oper := "";
	pick t := token {
		Operator =>
			oper = t.text;
		* =>
			raise t.unexpected(p);
	}
	return oper;
}

Parser.operator_maybe(p : self ref Parser) : string
{
	token := <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	oper := "";
	pick t := token {
		Operator or Comparitor =>
			return t.text;
		RightCBracket =>
			return ")";
		* =>
			raise t.unexpected(p);
	}
	return oper;
}


Parser.float_uservalue(p : self ref Parser) : (int, ref UserValue)
{
	name := p.label_typetag();
	min := p.number();
	o := p.operator();
	if(o != "-")
		raise "Unexpected " + o;
	max := p.number();
	(inargs, default)  := p.number_maybe();
	return (inargs, ref UserValue.Float(name, min, max, default));
}

Parser.int_uservalue(p : self ref Parser) : (int, ref UserValue)
{
	name := p.label_typetag();
	min := p.number();
	o := p.operator();
	if(o != "-")
		raise "Unexpected " + o;
	max := p.number();
	(inargs, default)  := p.number_maybe();
	return (inargs, ref UserValue.Int(name, min, max, default));
}

Parser.bool_uservalue(p : self ref Parser) : ref UserValue
{
	name := p.label();
	return ref UserValue.Bool(name);
}

Parser.color_uservalue(p : self ref Parser) : ref UserValue
{
	name := p.label();
	return ref UserValue.Color(name);
}

Parser.curve_uservalue(p : self ref Parser) : ref UserValue
{
	name := p.label();
	return ref UserValue.Curve(name);
}

Parser.gradient_uservalue(p : self ref Parser) : ref UserValue
{
	name := p.label();
	return ref UserValue.Gradient(name);
}

Parser.image_uservalue(p : self ref Parser, options : string) : ref UserValue
{
	name := p.label();
	return ref UserValue.Image(name, options);
}

Parser.uservalue(p : self ref Parser, tag : string) : (int, ref UserValue)
{
	arg : ref UserValue;
	arg = nil;
	inargs := 1;
	case tag {
	"float" =>
		(inargs, arg) = p.float_uservalue();
	"int" =>
		(inargs, arg) = p.int_uservalue();
	"bool" =>
		arg = p.bool_uservalue();
	"color" =>
		arg = p.color_uservalue();
	"gradient" =>
		arg = p.gradient_uservalue();
	"image" =>
		arg = p.image_uservalue("");
	* =>
		token := <- p.tokens;
		if(token == nil) raise "unexpected EOF";
		pick t := token {
		Label =>
			if(t.text != "image")
				raise t.unexpected(p);
			arg = p.image_uservalue(tag);
		* =>
			raise t.unexpected(p);
		}	
	}
	return (inargs, arg);
}

Parser.uservalues(p : self ref Parser) : (string, string)
{
	token : ref Token;
	token = <- p.tokens;
	pick t := token {
		LeftCBracket =>
			;
		* =>
			raise t.unexpected(p);
	}
	args := "";
	init := "";
	arg : ref UserValue;
	inargs := 1;
	do {
		# argument type
		token = <- p.tokens;
		if(token == nil) raise "unexpected EOF";
		pick t := token {
			Label =>
				(inargs, arg) = p.uservalue(t.text);
				if(arg != nil) {
					if(args != "")
						args += ",";
					(a, i) := arg.arg_init();
					args += a;
					init += i;
				} else {
					inargs = 0;
				}
			Comma =>
				;
			RightCBracket =>
				inargs = 0;
			* =>
				raise t.unexpected(p);
		}
	} while (inargs);
	if(args != "")
		args += ": ref UserValue";
	return (args, init);
}

Parser.argument(p : self ref Parser) : ref Argument
{
	token := <- p.tokens;
	if(token == nil) raise "Unexpected EOF";
	tag := "";
	unary := "";

	pick t := token {
		Label =>
			tag = t.text;
		Number =>
			tag = t.text;
		Operator =>
			if(t.text != "-" && t.text != "+")
				raise t.unexpected(p);
			unary = t.text;
		* =>
			raise t.unexpected(p);
	}
	token = <- p.tokens;
	if(token == nil) raise "Unexpected EOF";
	pick t := token {
		Label =>
			if(t.text == ",") {
				if(tag != "")
					return ref Argument.Literal(tag);
			}
			raise t.unexpected(p);
		Number =>
			if(unary == "" )
				raise t.unexpected(p);
			return ref Argument.Function(ref Function(t.text, p.arguments(ref Argument.Literal(unary))));
		Operator =>
			if(tag == "")
				raise t.unexpected(p);
			return ref Argument.Function(ref Function(t.text, p.arguments(ref Argument.Literal(tag))));
		RightCBracket =>
			return ref Argument.Function(ref Function(t.text, p.arguments(nil)));
		* =>
			raise t.unexpected(p);
	}
	return nil;
}

Parser.arguments(p : self ref Parser, firstarg : ref Argument) : array of ref Argument
{
	a : ref Argument;
	args : list of ref Argument;
	if(firstarg != nil)
		args = firstarg :: args;
	while((a = p.argument()) != nil)
		args = a :: args;
	aargs := array[len(args)] of ref Argument;
	for(i := len(args) - 1; i >= 0  ; i--) {
		aargs[i] = hd args;
		args = tl args;
	}
	return aargs;
}

Parser.rhs(p : self ref Parser, bracket : string)
{
	if(bracket != "")
		sys->print(")");
}

Parser.is_filter(p : self ref Parser, label : string) : string
{
	for(filters := p.filters; filters != nil; filters = tl filters)
		if((hd filters).name == label)
			return label;
	return nil;
}

Parser.is_variable(p : self ref Parser, label : string) : string
{
	for(variables := p.variables; variables != nil; variables = tl variables)
		if(hd variables == label)
			return label;
	return nil;
}

Parser.value(p : self ref Parser)
{
	token : ref Token;
	i := 0;
	token = <- p.tokens;
	if(token != nil) {
		pick t := token {
		Label =>
			fname := p.is_filter(t.text);
			if(fname != "") {
				sys->print("%s(", fname);
				p.value();
				sys->print(")");
			} else {
				var := p.is_variable(t.text);
				if(var == "") {
					raise t.unexpected(p);
				}
			}
		Number =>
			if(i++ > 0)
				sys->print(" %s", t.text);
			else
				sys->print("%s", t.text);
		LeftCBracket =>
			sys->print("(");
			p.value();
			token = <- p.tokens;
			pick tt := token {
				RightCBracket =>
					sys->print(")");
				* =>
					raise t.unexpected(p);
			}
		* =>
			raise t.unexpected(p);
		}
	}
}

Parser.conditional(p : self ref Parser)
{
	token : ref Token;
	p.value();
	token = <- p.tokens;
	pick t := token {
	Comparitor =>
		sys->print("%s", t.text);
	*  =>
		raise t.unexpected(p);
	}
	p.value();
}

Parser.code(p : self ref Parser)
{
	token : ref Token;
	codes : list of ref Code;
	conditions := 0;
	while((token = <- p.tokens) != nil) {
		pick t := token {
		Keyword =>
			case t.text {
			"if" =>
				conditions++;
				sys->print("if(");
				p.conditional();
				sys->print(") {\n");
			"else" =>
				if(conditions == 0)
					raise "Unexpected else";
				sys->print("} else {");
			"end" =>
				if(conditions == 0)
					sys->print("return pixel;\n};\n");
				else {
					conditions--;
					sys->print("}");
				}
			}
		Label =>
			nextt := <- p.tokens;
			pick n := nextt {
			Operator =>
				if(n.text == "=") {
					sys->print("%s = ", t.text);
					p.rhs("");
				}
			LeftCBracket =>
				sys->print("pixel = %s(", t.text);
				p.rhs("(");
			Keyword =>
				if(n.text == "end")
					sys->print("pixel = %s;\n", t.text);
			}
		Function =>
			sys->print("RGBA = %s", t.text);
			nextt := <- p.tokens;
			pick n := nextt {
			LeftCBracket =>
				sys->print("(");
				p.value();
				nexttt := <- p.tokens;
				pick nn := nexttt {
					RightCBracket =>
						sys->print(");\n");
					* =>
						raise t.unexpected(p);
				}
			*  =>
				raise t.unexpected(p);
			}
		*  =>
			raise t.unexpected(p);
						
		}
	}
}

Parser.filter(p : self ref Parser, options : list of string) : ref Filter
{
	token : ref Token;
	token = <- p.tokens;
	if(token == nil) raise "unexpected EOF";
	name : string;
	pick t := token {
		Label =>
			if (t.typetag != "")
				raise "Bad filter name";
			name = t.text;
		*  =>
			raise t.unexpected(p);
	}

	(args, init) := p.uservalues();
	sys->print("mm_%s(%s) : ref RGBA\n{\n%s", name, args, init);
	for(o := options; o != nil; o = tl options)
		sys->print("set_option(\"%s\")\n", hd o);
	p.code();
	return nil;
}



init() 
{
	sys = load Sys Sys->PATH;
	bufio = load Bufio Bufio->PATH;
	str = load String String->PATH;
	
	functions = "abs" :: "acos" :: "acosh" :: "alpha" :: "arg" :: "asin" :: "asinh" :: "atan" :: "atan" :: "atanh" :: "beta" :: "blue" :: "ceil" :: "clamp" :: "conj" :: "cos" :: "cosh" :: "crossp" :: "deg2rad" :: "det" :: "dotp" :: "ell_int_D" :: "ell_int_E" :: "ell_int_Ecomp" :: "ell_int_F" :: "ell_int_Kcomp" :: "ell_int_P" :: "ell_int_RC" :: "ell_int_RD" :: "ell_int_RF" :: "ell_int_RJ" :: "ell_jac_cn" :: "ell_jac_dn" :: "ell_jac_sn" :: "exp" :: "floor" :: "gamma" :: "gray" :: "grayColor" :: "grayaColor" :: "green" :: "inintv" :: "lerp" :: "log" :: "max" :: "min" :: "noise" :: "normalize" :: "pmod" :: "print" :: "rad2deg" :: "rand" :: "red" :: "rgbColor" :: "rgbaColor" :: "scale" :: "sign" :: "sin" :: "sinh" :: "sqrt" :: "sum" :: "tan" :: "tanh" :: "toHSVA" :: "toRA" :: "toRGBA" :: "toXY" :: nil;
	pre_defined_vars = "xy" :: "x" :: "y" :: "ra" :: "r" :: "a" :: "WH" :: "W" :: "H" :: "R" :: "XY" :: "X" :: "Y" :: "t" :: "frame" :: "pi" :: "e" :: "I" :: nil;
}

Parser.parse(p : self ref Parser)
{
	token : ref Token;

	options : list of string;
	options = nil;

	while((token = <- p.tokens) != nil) {
		pick t := token {
			Label =>
				case t.text {
				"filter" =>
					p.filter(options);
				* =>
					options = t.text :: options;
				}
			*  =>
				raise t.unexpected(p);
		}

	}
}

parse(fname : string)
{
	if(sys == nil) init();

	p := ref Parser(fname, 1, chan of ref Token, nil, nil);
	spawn p.tokenizer();

	p.parse();

}
	

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.