changeset 273:0dc7322590da

Make import:from actually work. Fix some macro bugs. Add a cpointer primitive type for storing an opaque pointer to a C object.
author Michael Pavone <pavone@retrodev.com>
date Sun, 20 Jul 2014 00:12:43 -0700
parents bb2b4613fdc8
children a923b5b7da3d
files cbackend.js compiler.js interp.js
diffstat 3 files changed, 70 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/cbackend.js	Sat Jul 19 20:18:34 2014 -0700
+++ b/cbackend.js	Sun Jul 20 00:12:43 2014 -0700
@@ -106,6 +106,13 @@
 symbol.prototype.toCTypeName = function() {
 	return this.cleanName();
 };
+symbol.prototype.cSafeName = function() {
+	var name = this.cleanName();
+	if (name[0] >= "0" && name[0] <= "9") {
+		name = '_tp_' + name;
+	}
+	return name;
+};
 symbol.prototype.toCLLExpr = function(vars) {
 	var name = this.cleanName();
 	if (name in vars) {
@@ -121,13 +128,13 @@
 		info = symbols.find(name, false, true);
 	}
 	if (!info) {
-		return name;
+		return this.cSafeName();
 	}
 	if (info.type == 'toplevel') {
 		return toplevel.moduleVar(name);
 	} else if (info.type == 'self') {
 		if (info.isll || !(info.def instanceof lambda)) {
-			return 'self->' + name;
+			return 'self->' + this.cSafeName();
 		} else {
 			return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, self)';
 		}
@@ -417,6 +424,7 @@
 	this.parent = 'NULL';
 	this.init = [];
 	this.initmsgadded = false;
+	this.imported = [];
 }
 
 cObject.prototype.addInclude = function(includefile) {
@@ -467,14 +475,19 @@
 };
 
 cObject.prototype.addImport = function(symbols, source) {
-	this.imported.push(source);
-	var importNum = imported.length - 1;
+	var importNum = this.imported.indexOf(source);
+	if (importNum < 0) {
+		var importNum = this.imported.length;
+		this.imported.push(source);
+		this.addInit('self->import_' + importNum + ' = ' + source.toC() + ';');
+	}
 	if (symbols) {
+		var self = this;
 		each(symbols, function(i, sym) {
-			this.addMessage(sym.name, {
+			self.addMessage(sym.name, {
 				vars: {},
 				lines: [
-					'return self->import_' + importNum + '->meta->meth_lookup[method_id & 0xF](method_id, num_args, self->import_' + importNum + ', args);'
+					'return self->import_' + importNum + '->meta->meth_lookup[method_id & 0xF](method_id, num_params, self->import_' + importNum + ', args);'
 				]
 			});
 		});
@@ -515,6 +528,9 @@
 			objdef += '\tobject * ' + this.properties[i] + ';\n'
 		}
 	}
+	for (var i in this.imported) {
+		objdef += '\tobject * import_' + i + ';\n';
+	}
 	objdef += '} ' + this.name + ';\nobj_meta ' + this.name + '_meta;\n';
 	return includes + objdef;
 }
@@ -604,9 +620,13 @@
 	}
 	for (var i in messages) {
 		if (messages[i] instanceof funcall) {
-			if (messages[i].name == 'import:' && messages[i].args.length == 1) {
+			var msgname = messages[i].name;
+			if (msgname[msgname.length-1] == ':') {
+				msgname = msgname.substr(0, msgname.length-1);
+			}
+			if (msgname == 'import' && messages[i].args.length == 1) {
 				me.addImport(false, messages[i].args[0]);
-			} else if(messages[i].name == 'import:from:' && messages[i].args.length == 2) {
+			} else if(msgname == 'import:from' && messages[i].args.length == 2) {
 				var importsyms = [];
 				each(messages[i].args[0].val, function(i, el) {
 					if (!(el instanceof symbol)) {
@@ -615,9 +635,9 @@
 					importsyms.push(el);
 				});
 				me.addImport(importsyms, messages[i].args[1]);
-			} else if(messages[i].name == 'llProperty:withType:' && messages[i].args.length == 2) {
+			} else if(msgname == 'llProperty:withType' && messages[i].args.length == 2) {
 				me.addProperty(messages[i].args[0].name, null, messages[i].args[1].toCTypeName());
-			} else if(messages[i].name == 'llMessage:withVars:andCode:' && messages[i].args.length == 3) {
+			} else if(msgname == 'llMessage:withVars:andCode' && messages[i].args.length == 3) {
 				if (messages[i].args[0] instanceof symbol) {
 					var msgname = messages[i].args[0].name;
 				} else if (messages[i].args[0] instanceof strlit) {
@@ -628,13 +648,13 @@
 				var rawvars = messages[i].args[1].expressions;
 				var vars = {};
 				for(var v in rawvars) {
-					vars[rawvars[v].symbol.name] = rawvars[v].expression.toCTypeName();
+					vars[rawvars[v].symbol.cSafeName()] = rawvars[v].expression.toCTypeName();
 				}
 				me.addMessage(msgname, {
 					vars: vars,
 					lines: messages[i].args[2].toCLines(vars, true)
 				});
-			} else if(messages[i].name == 'includeSystemHeader:' && messages[i].args.length == 1) {
+			} else if(msgname == 'includeSystemHeader' && messages[i].args.length == 1) {
 				me.addInclude("<" + messages[i].args[0].val + ">");
 			} else {
 
@@ -786,6 +806,29 @@
 	return intObj;
 }
 
+function makeCPointer()
+{	
+	var cptr = new cObject('cpointer');
+	cptr.addProperty('val', null, 'void *');
+	//cpointer: 
+	//1234567890
+	cptr.addMessage('string', {
+		vars: {ret: 'string *'},
+		lines: [
+			'ret = make_object(&string_meta, NULL, 0);',
+			//22 digits for worst case sensible representation
+			//10 chars for prefix
+			//4 for slop
+			//1 for null terminator
+			'ret->data = GC_MALLOC_ATOMIC(22+10+4+1);',
+			'snprintf(ret->data, 22+10+4, "cpointer: %p", self->val);',
+			'ret->data[22+10+4] = 0;',
+			'return (object *)ret;'
+		]
+	});
+	return cptr;
+}
+
 function makeArray()
 {
 	var arrayfile = toplevel.names['array'];
@@ -827,7 +870,7 @@
 {
 	return [makeInt(64, false), makeInt(32, false), makeInt(16, false), makeInt(8, false),
 	        makeInt(64, true) , makeInt(32, true),  makeInt(16, true),  makeInt(8, true),
-	        makeArray(), makeString(), makelambda()];
+	        makeArray(), makeString(), makelambda(), makeCPointer()];
 }
 
 function addBuiltinModules(toplevel)
--- a/compiler.js	Sat Jul 19 20:18:34 2014 -0700
+++ b/compiler.js	Sun Jul 20 00:12:43 2014 -0700
@@ -380,6 +380,13 @@
 		} else {
 			throw new Error("Unexpected AST type for foreign:");
 		}
+	} else if (this.name == 'import:from:' && symbols instanceof osymbols  && this.args.length == 2) {
+		each(this.args[0].val, function(i, el) {
+			if (!(el instanceof symbol)) {
+				throw new Error('Names in import:from statement must be symbols');
+			}
+			symbols.defineMsg(el.name, new lambda([], []));
+		});
 	} else if (this.name == 'llProperty:withType:') {
 		if (this.args[0] instanceof symbol) {
 			if ((this.args[1] instanceof symbol) || (this.args[1] instanceof funcall)) {
@@ -391,10 +398,11 @@
 		} else {
 			throw new Error("First argument to llProperty:withType: must be a symbol or string");
 		}
-	} else if (this.name == 'llMessage:withVars:andCode:') {
+	} else if (this.name == 'llMessage:withVars:andCode:' && symbols instanceof osymbols) {
 		if (this.args[0] instanceof symbol || this.args[0] instanceof strlit) {
 			if (this.args[1] instanceof lambda) {
 				if (this.args[2] instanceof lambda) {
+					
 					symbols.defineMsg(this.args[0].name, this.args[2]);
 					isll = true;
 				} else {
--- a/interp.js	Sat Jul 19 20:18:34 2014 -0700
+++ b/interp.js	Sun Jul 20 00:12:43 2014 -0700
@@ -757,14 +757,15 @@
 	for (var i = 0; i < this.args.length; i++) {
 		env.syms[this.args[i].cleanName()] = {};
 	}
+	var outexprs = []
 	for (var i = 0; i < this.expressions.length; i++) {
 		var expr = this.expressions[i];
 		if (expr instanceof assignment) {
 			if (expr.expression instanceof funcall && expr.expression.name == 'macro:') {
-				env.defMacro(expr.symbol.name, exp.expression.args[0].eval(env));
+				env.defMacro(expr.symbol.name, expr.expression.args[0].eval(env));
 			} else {
 				env.syms[expr.symbol.cleanName()] = {};
-				this.expressions[i] = expr.macroexpand(env);
+				outexprs.push(expr.macroexpand(env));
 				try {
 					if (this.expressions[i].expression.isconstant()) {
 						env.syms[expr.symbol.cleanName()] = this.expressions[i].expression.eval(env);
@@ -780,9 +781,10 @@
 				}
 			}
 		} else {
-			this.expressions[i] = expr.macroexpand(env);
+			outexprs.push(expr.macroexpand(env));
 		}
 	}
+	this.expressions = outexprs;
 	return this;
 };