mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-18 22:41:18 +00:00
Add a few additional syntax checks.
Throw an error if a method uses a parameter name that is also an ivar name.
Stop using with{} block for class methods.
This commit is contained in:
1 parent
bbbae36e6a
commit
7013b34897
1 file changed
+70
-21
+70
-21
@@ -171,9 +171,37 @@ var Preprocessor = function(/*String*/ aString, /*CFURL|String*/ aURL, /*unsigne
|
||||
this._classMethod = false;
|
||||
this._executable = NULL;
|
||||
|
||||
this._classLookupTable = {};
|
||||
|
||||
this.preprocess(this._tokens, this._buffer);
|
||||
}
|
||||
|
||||
Preprocessor.prototype.setClassInfo = function(className, superClassName, ivars)
|
||||
{
|
||||
this._classLookupTable[className] = {superClassName:superClassName, ivars:ivars};
|
||||
}
|
||||
|
||||
Preprocessor.prototype.getClassInfo = function(className)
|
||||
{
|
||||
return this._classLookupTable[className];
|
||||
}
|
||||
|
||||
Preprocessor.prototype.allIvarNamesForClassName = function(className)
|
||||
{
|
||||
var names = {},
|
||||
classInfo = this.getClassInfo(className);
|
||||
|
||||
while (classInfo)
|
||||
{
|
||||
for (var i in classInfo.ivars)
|
||||
names[i] = 1;
|
||||
|
||||
classInfo = this.getClassInfo(classInfo.superClassName);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
exports.Preprocessor = Preprocessor;
|
||||
|
||||
Preprocessor.Flags = { };
|
||||
@@ -384,9 +412,9 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
// If we are at an opening curly brace ('{'), then we have an ivar declaration.
|
||||
if (token == TOKEN_OPEN_BRACE)
|
||||
{
|
||||
var ivar_count = 0,
|
||||
var ivar_names = {},
|
||||
ivar_count = 0,
|
||||
declaration = [],
|
||||
|
||||
attributes,
|
||||
accessors = {};
|
||||
|
||||
@@ -402,15 +430,16 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
}
|
||||
else if (token == TOKEN_SEMICOLON)
|
||||
{
|
||||
if (ivar_count++ == 0)
|
||||
if (ivar_count++ === 0)
|
||||
CONCAT(buffer, "class_addIvars(the_class, [");
|
||||
else
|
||||
CONCAT(buffer, ", ");
|
||||
|
||||
|
||||
var name = declaration[declaration.length - 1];
|
||||
|
||||
|
||||
CONCAT(buffer, "new objj_ivar(\"" + name + "\")");
|
||||
|
||||
ivar_names[name] = 1;
|
||||
declaration = [];
|
||||
|
||||
if (attributes)
|
||||
@@ -422,7 +451,7 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
else
|
||||
declaration.push(token);
|
||||
}
|
||||
|
||||
|
||||
// If we have objects in our declaration, the user forgot a ';'.
|
||||
if (declaration.length)
|
||||
throw new SyntaxError(this.error_message("*** Expected ';' in ivar declaration, found '}'."));
|
||||
@@ -433,6 +462,11 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
if (!token)
|
||||
throw new SyntaxError(this.error_message("*** Expected '}'"));
|
||||
|
||||
this.setClassInfo(class_name, superclass_name === "Nil" ? null : superclass_name, ivar_names);
|
||||
|
||||
// build up the list of illegal method param names
|
||||
var ivar_names = this.allIvarNamesForClassName(class_name);
|
||||
|
||||
for (ivar_name in accessors)
|
||||
{
|
||||
var accessor = accessors[ivar_name],
|
||||
@@ -445,7 +479,7 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
if (IS_NOT_EMPTY(instance_methods))
|
||||
CONCAT(instance_methods, ",\n");
|
||||
|
||||
CONCAT(instance_methods, this.method(new Lexer(getterCode)));
|
||||
CONCAT(instance_methods, this.method(new Lexer(getterCode), ivar_names));
|
||||
|
||||
// setter
|
||||
if (accessor["readonly"])
|
||||
@@ -469,7 +503,7 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
if (IS_NOT_EMPTY(instance_methods))
|
||||
CONCAT(instance_methods, ",\n");
|
||||
|
||||
CONCAT(instance_methods, this.method(new Lexer(setterCode)));
|
||||
CONCAT(instance_methods, this.method(new Lexer(setterCode), ivar_names));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -478,7 +512,10 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
// We must make a new class object for our class definition.
|
||||
CONCAT(buffer, "objj_registerClassPair(the_class);\n");
|
||||
}
|
||||
|
||||
|
||||
if (!ivar_names)
|
||||
var ivar_names = this.allIvarNamesForClassName(class_name);
|
||||
|
||||
while ((token = tokens.skip_whitespace()))
|
||||
{
|
||||
if (token == TOKEN_PLUS)
|
||||
@@ -490,7 +527,6 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
|
||||
CONCAT(class_methods, this.method(tokens));
|
||||
}
|
||||
|
||||
else if (token == TOKEN_MINUS)
|
||||
{
|
||||
this._classMethod = false;
|
||||
@@ -498,19 +534,19 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
|
||||
if (IS_NOT_EMPTY(instance_methods))
|
||||
CONCAT(instance_methods, ", ");
|
||||
|
||||
CONCAT(instance_methods, this.method(tokens));
|
||||
CONCAT(instance_methods, this.method(tokens, ivar_names));
|
||||
}
|
||||
|
||||
// Check if we've reached @end...
|
||||
else if (token == TOKEN_PREPROCESSOR)
|
||||
{
|
||||
// The only preprocessor directive we should ever encounter at this point is @end.
|
||||
if ((token = tokens.next()) == TOKEN_END)
|
||||
break;
|
||||
|
||||
else
|
||||
throw new SyntaxError(this.error_message("*** Expected \"@end\", found \"@" + token + "\"."));
|
||||
}
|
||||
else
|
||||
throw new SyntaxError(this.error_message("*** Expected a method declaration, or \"@end\", found \"" + token + "\"."));
|
||||
}
|
||||
|
||||
if (IS_NOT_EMPTY(instance_methods))
|
||||
@@ -560,14 +596,16 @@ Preprocessor.prototype._import = function(tokens)
|
||||
this._dependencies.push(new FileDependency(new CFURL(URLString), isQuoted));
|
||||
}
|
||||
|
||||
Preprocessor.prototype.method = function(/*Lexer*/ tokens)
|
||||
Preprocessor.prototype.method = function(/*Lexer*/ tokens, ivar_names)
|
||||
{
|
||||
var buffer = new StringBuffer(),
|
||||
token,
|
||||
selector = "",
|
||||
parameters = [],
|
||||
types = [null];
|
||||
|
||||
|
||||
ivar_names = ivar_names || {};
|
||||
|
||||
while((token = tokens.skip_whitespace()) && token != TOKEN_OPEN_BRACE)
|
||||
{
|
||||
if (token == TOKEN_COLON)
|
||||
@@ -593,8 +631,10 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
|
||||
|
||||
// Since this follows a colon, this must be the parameter name.
|
||||
parameters[parameters.length] = token;
|
||||
|
||||
if (token in ivar_names)
|
||||
throw new SyntaxError(this.error_message("*** Method ( "+selector+" ) uses a parameter name that is already in use ( "+token+" )"));
|
||||
}
|
||||
|
||||
else if (token == TOKEN_OPEN_PARENTHESIS)
|
||||
{
|
||||
var type = "";
|
||||
@@ -606,7 +646,6 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
|
||||
// types[0] is the return argument
|
||||
types[0] = type || null;
|
||||
}
|
||||
|
||||
// Argument list ", ..."
|
||||
else if (token == TOKEN_COMMA)
|
||||
{
|
||||
@@ -616,7 +655,6 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
|
||||
|
||||
// FIXME: Shouldn't allow any more after this.
|
||||
}
|
||||
|
||||
// Build selector name.
|
||||
else
|
||||
selector += token;
|
||||
@@ -642,12 +680,23 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
|
||||
CONCAT(buffer, parameters[index]);
|
||||
}
|
||||
|
||||
CONCAT(buffer, ")\n{ with(self)\n{");
|
||||
CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE));
|
||||
CONCAT(buffer, "}\n}");
|
||||
if (this._classMethod)
|
||||
{
|
||||
CONCAT(buffer, ")\n{");
|
||||
CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE));
|
||||
CONCAT(buffer, "}");
|
||||
}
|
||||
else
|
||||
{
|
||||
CONCAT(buffer, ")\n{ with(self)\n{");
|
||||
CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE));
|
||||
CONCAT(buffer, "}\n}");
|
||||
}
|
||||
|
||||
// TODO: actually use Flags.IncludeTypeSignatures flag instead of tying to Flags.IncludeDebugSymbols
|
||||
if (this._flags & Preprocessor.Flags.IncludeDebugSymbols) //flags.IncludeTypeSignatures)
|
||||
CONCAT(buffer, ","+JSON.stringify(types));
|
||||
|
||||
CONCAT(buffer, ")");
|
||||
|
||||
this._currentSelector = "";
|
||||
|
||||
Reference in new issue
Block a user