Skip to content

Commit

Permalink
feature: exception base all from $Error
Browse files Browse the repository at this point in the history
  • Loading branch information
peze authored and JacksonTian committed Jan 16, 2024
1 parent 89af05d commit 28442ae
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 31 deletions.
79 changes: 51 additions & 28 deletions lib/semantic.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ function isAssignable(expected, actual, expr) {
return true;
}

// $Error vs exception
if(expected.name === '$Error' && actual.isException) {
return true;
}

if (isExtendOn(expected, actual)) {
return true;
}
Expand Down Expand Up @@ -330,6 +335,11 @@ function eql(expects, actuals) {
continue;
}

// $Error vs exception
if(expect.name === '$Error' && actual.isException) {
continue;
}

if (isExtendOn(expect, actual)) {
continue;
}
Expand Down Expand Up @@ -510,8 +520,8 @@ class TypeChecker {
throw new SyntaxError(message);
}

findProperty(model, propName) {
const find = model.modelBody.nodes.find((item) => {
findProperty(model, propName, isException = false) {
let find = model.modelBody.nodes.find((item) => {
return item.fieldName.lexeme === propName;
});
if(find) {
Expand All @@ -521,12 +531,15 @@ class TypeChecker {
};
}

if(!model.extendOn) {
if(!model.extendOn && !isException) {
return;
}
let extendModel, moduleName;

if (model.extendOn.type === 'moduleModel') {

if(!model.extendOn && isException) {
extendModel = builtin.get('$Error');
isException = false;
} else if (model.extendOn.type === 'moduleModel') {
const [ main, ...path ] = model.extendOn.path;
moduleName = main.lexeme;
const checker = this.dependencies.get(moduleName);
Expand All @@ -545,9 +558,13 @@ class TypeChecker {
extendModel = this.models.get(model.extendOn.lexeme);
}

find = this.findProperty(extendModel, propName, isException);
if(!find) {
return;
}
return {
moduleName,
...this.findProperty(extendModel, propName)
...find
};
}

Expand All @@ -562,6 +579,7 @@ class TypeChecker {
if (this.models.has(key)) {
this.error(`redefined model or exception "${key}"`, name);
}

this.models.set(key, node);
});

Expand Down Expand Up @@ -1871,7 +1889,7 @@ class TypeChecker {
for (let i = 0; i < ast.propertyPath.length; i++) {
let prop = ast.propertyPath[i];
currentPath.push(prop.lexeme);
let find = this.findProperty(current, prop.lexeme);
let find = this.findProperty(current, prop.lexeme, current.isException);
if (!find) {
this.error(`The model ${currentPath.join('.')} is undefined`, prop);
}
Expand Down Expand Up @@ -2070,25 +2088,27 @@ class TypeChecker {
const name = field.fieldName.lexeme;
let find;
if (ast.aliasId.isModel) {
find = this.findProperty(model, name);
find = this.findProperty(model, name, model.isException);
if (!find) {
this.error(`the property "${name}" is undefined in model "${modelName}"`, field.fieldName);
}
} else {
const checker = this.dependencies.get(aliasId);
find = checker.findProperty(model, name);
}

if (!find) {
this.error(`the property "${name}" is undefined in model "${aliasId}.${modelName}"`, field.fieldName);
find = checker.findProperty(model, name, model.isException);
if (!find) {
this.error(`the property "${name}" is undefined in model "${aliasId}.${modelName}"`, field.fieldName);
}
}
modelName = find.modelName;
const currentModelName = find.modelName;
const modelField = find.modelField;
const type = this.getExprType(field.expr, env);
const moduleName = find.moduleName || aliasId;
let expected;
if (ast.aliasId.isModel) {
expected = this.getFieldType(modelField, modelName);
expected = this.getFieldType(modelField, currentModelName);
} else {
const checker = this.dependencies.get(aliasId);
expected = checker.getFieldType(modelField, modelName, moduleName);
expected = checker.getFieldType(modelField, currentModelName, moduleName);
}


Expand All @@ -2114,6 +2134,7 @@ class TypeChecker {
if (!model) {
this.error(`the model "${modelId}" is undefined in module "${aliasId}"`, ast.propertyPath[0]);
}
ast.aliasId.isException = model.isException;

this.usedExternModel.get(aliasId).add(modelId);
this.checkConstructModelFields(ast, model, `${modelId}`, env);
Expand All @@ -2131,6 +2152,7 @@ class TypeChecker {
if (this.models.has(aliasId)) {
const model = this.models.get(aliasId);
ast.aliasId.isModel = true;
ast.aliasId.isException = model.isException;
if (ast.propertyPath.length === 0) {
this.checkConstructModelFields(ast, model, aliasId, env);
return;
Expand Down Expand Up @@ -2292,7 +2314,6 @@ class TypeChecker {

actual.push(type);
}

if (!eql(expected, actual)) {
this.error(`the parameter` +
` types are mismatched. expected ` +
Expand Down Expand Up @@ -2398,20 +2419,17 @@ class TypeChecker {
}

if (type.type === 'model') {
let model, modelName, checker = this;
let model, checker = this;
if (type.moduleName) {
checker = this.dependencies.get(type.moduleName);
model = checker.models.get(type.name);
modelName = `${type.moduleName}.${type.name}`;
} else if (builtin.has(type.name)) {
model = builtin.get(type.name);
modelName = type.name;
} else {
model = this.models.get(type.name);
modelName = type.name;
}

const find = checker.findProperty(model, propName, modelName);
const find = checker.findProperty(model, propName, model.isException);
if (!find) {
return;
}
Expand Down Expand Up @@ -2592,16 +2610,20 @@ class TypeChecker {

if (ast.type === 'construct_model') {
if (ast.aliasId.isModel) {
return this.getModel([ast.aliasId.lexeme, ...ast.propertyPath.map((item) => {
const model = this.getModel([ast.aliasId.lexeme, ...ast.propertyPath.map((item) => {
return item.lexeme;
})].join('.'));
model.isException = ast.aliasId.isException;
return model;
}

const moduleName = ast.aliasId.lexeme;
const checker = this.dependencies.get(moduleName);
return checker.getModel(ast.propertyPath.map((item) => {
const model = checker.getModel(ast.propertyPath.map((item) => {
return item.lexeme;
}).join('.'), ast.aliasId.lexeme);
model.isException = ast.aliasId.isException;
return model;
}

if (ast.type === 'array') {
Expand Down Expand Up @@ -3037,7 +3059,7 @@ class TypeChecker {
}
}

flatModel(root, modelBody, modelName, extendOn) {
flatModel(root, modelBody, modelName, extendOn, type = 'model') {
const keys = new Map();
for (var i = 0; i < modelBody.nodes.length; i++) {
const node = modelBody.nodes[i];
Expand Down Expand Up @@ -3089,7 +3111,8 @@ class TypeChecker {
}

this.models.set(modelName, {
type: 'model',
type: type,
isException: type === 'exception',
extendOn: extendOn,
modelName: {
tag: Tag.ID,
Expand All @@ -3103,13 +3126,13 @@ class TypeChecker {
visitModel(ast) {
assert.equal(ast.type, 'model');
const modelName = ast.modelName.lexeme;
this.flatModel(ast, ast.modelBody, modelName, ast.extendOn);
this.flatModel(ast, ast.modelBody, modelName, ast.extendOn, ast.type);
}

visitException(ast) {
assert.equal(ast.type, 'exception');
const exceptionName = ast.exceptionName.lexeme;
this.flatModel(ast, ast.exceptionBody, exceptionName, ast.extendOn);
this.flatModel(ast, ast.exceptionBody, exceptionName, ast.extendOn, ast.type);
}

visitEnum(ast) {
Expand Down
10 changes: 8 additions & 2 deletions test/fixtures/extend_model/main.dara
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ model DeriveSubFile extends Util.ExtendSubFile {
}


static function getFile(efile: OSS.File, file: OSS.File, err: OSS.SubFile.file): void;
static function getFile(efile: OSS.File, file: OSS.File, err: OSS.SubFile.file, err2: $Error): void;

static function call(size: number): void {
var file = new Util.mainFile{
name = 'name',
size = 100,
};
var baseErr: $Error = new Util.ExtendSubFileError{
name = 'name',
size = 100,
code = 'Error',
message = 'error message',
};
var maps = {
key = new Util.ExtendSubFileError{
name = 'name',
Expand Down Expand Up @@ -54,7 +60,7 @@ static function call(size: number): void {
name = 'name',
size = 100,
};
getFile(efile, file, err);
getFile(efile, file, err, err);
}

}
1 change: 1 addition & 0 deletions test/import.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ function callOSS(): string {
expect(function () {
readAndParse('fixtures/import_module_model/undefined_model.dara');
}).to.throwException(function (e) {
console.log(e);
expect(e).to.be.a(SyntaxError);
expect(e.message).to.be(`the model "ConfigX" is undefined in module "OSS"`);
});
Expand Down
Loading

0 comments on commit 28442ae

Please sign in to comment.