Skip to content

Commit

Permalink
add try catch upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
peze authored and JacksonTian committed Dec 25, 2023
1 parent 20e88c5 commit abf18dd
Show file tree
Hide file tree
Showing 8 changed files with 873 additions and 59 deletions.
26 changes: 24 additions & 2 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2001,20 +2001,41 @@ class Parser extends BaseParser {
const begin = this.getIndex();
this.match(Tag.TRY);
let tryStmts = this.blockStmts();
const catchBlocks = [];
let catchStmts = null;
let id = null;
let finallyStmts = null;
let end;
if (this.look.tag === Tag.CATCH || this.look.tag === Tag.FINALLY) {
if (this.look.tag === Tag.CATCH) {
while(this.look.tag === Tag.CATCH) {
this.move();
this.match('(');
id = this.look;
const catchId = this.look;
this.match(Tag.ID);
if(this.is(')')) {
// compatible with v1
// only can be last catch block
this.move();
id = catchId;
catchStmts = this.blockStmts();
catchBlocks.push({
id: catchId,
catchStmts,
});
end = catchStmts.tokenRange[1];
break;
}
this.match(':');
catchId.type = this.baseType();
this.match(')');
catchStmts = this.blockStmts();
catchBlocks.push({
id: catchId,
catchStmts,
});
end = catchStmts.tokenRange[1];
}

if (this.look.tag === Tag.FINALLY) {
this.move();
finallyStmts = this.blockStmts();
Expand All @@ -2029,6 +2050,7 @@ class Parser extends BaseParser {
tryBlock: tryStmts,
catchId: id,
catchBlock: catchStmts,
catchBlocks: catchBlocks,
finallyBlock: finallyStmts,
tokenRange: [begin, end]
};
Expand Down
127 changes: 70 additions & 57 deletions lib/semantic.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,11 +524,12 @@ class TypeChecker {
if(!model.extendOn) {
return;
}
let extendModel;
let extendModel, moduleName;

if (model.extendOn.type === 'moduleModel') {
const [ main, ...path ] = model.extendOn.path;
const checker = this.dependencies.get(main.lexeme);
moduleName = main.lexeme;
const checker = this.dependencies.get(moduleName);
const typeName = path.map((item) => {
return item.lexeme;
}).join('.');
Expand All @@ -544,7 +545,10 @@ class TypeChecker {
extendModel = this.models.get(model.extendOn.lexeme);
}

return this.findProperty(extendModel, propName);
return {
moduleName,
...this.findProperty(extendModel, propName)
};
}

checkModels(ast) {
Expand Down Expand Up @@ -807,11 +811,11 @@ class TypeChecker {

getExtendOn(ast, moduleName) {
let extendOn = [];
let extendModel, name;
let extendModel, name, checker;
if (ast.type === 'moduleModel') {
const [ main, ...path ] = ast.path;
moduleName = main.lexeme;
const checker = this.dependencies.get(moduleName);
checker = this.dependencies.get(moduleName);
name = path.map((item) => {
return item.lexeme;
}).join('.');
Expand All @@ -835,9 +839,7 @@ class TypeChecker {
extendOn.push(_model(name, moduleName));

if(extendModel.extendOn) {
const checker = moduleName ? this.dependencies.get(moduleName) : this;
const ast = checker.modelDep.get(extendModel.modelName.lexeme);
extendOn = extendOn.concat(checker.getExtendOn(ast, moduleName));
extendOn = extendOn.concat(this.getExtendOn(extendModel.extendOn, moduleName));
}
return extendOn;
}
Expand Down Expand Up @@ -1281,15 +1283,20 @@ class TypeChecker {
visitTry(ast, env) {
assert.equal(ast.type, 'try');
this.visitStmts(ast.tryBlock, env);
if (ast.catchBlock) {
ast.catchBlocks.forEach(block => {
// create new local
var local = new Env(env.local);
local.set(ast.catchId.lexeme, _model('$Error'));
let type = _model('$Error');
if(block.id.type) {
this.checkType(block.id.type);
type = this.getType(block.id.type);
}
local.set(block.id.lexeme, type);
env.local = local;
this.visitStmts(ast.catchBlock, env);
this.visitStmts(block.catchStmts, env);
// restore the local
env.local = env.local.preEnv;
}
});

if (ast.finallyBlock) {
this.visitStmts(ast.finallyBlock, env);
Expand Down Expand Up @@ -1821,11 +1828,40 @@ class TypeChecker {
replace(ast, target);
return;
}

this.checkId(ast.id, env);


// check property
const type = this.getVariableType(ast.id, env);
ast.id.inferred = type;

if (type.type === 'model' || type.type === 'map') {
// { type: 'map', keyTypeName: 'string', valueTypeName: 'any' }
const currentPath = [ast.id.lexeme];
let current = type;
ast.propertyPathTypes = new Array(ast.propertyPath.length);
for (let i = 0; i < ast.propertyPath.length; i++) {

let prop = ast.propertyPath[i];

let find = this.getPropertyType(current, prop.lexeme);
if (!find) {
this.error(`The property ${prop.lexeme} is undefined ` +
`in model ${currentPath.join('.')}(${current.name})`, prop);
}
ast.propertyPathTypes[i] = find;
currentPath.push(prop.lexeme);
current = find;
}

return;
}

if (this.models.has(ast.id.lexeme)) {
// submodel M.N
let current = this.models.get(ast.id.lexeme);

const currentPath = [ast.id.lexeme];
for (let i = 0; i < ast.propertyPath.length; i++) {
let prop = ast.propertyPath[i];
Expand Down Expand Up @@ -1853,30 +1889,6 @@ class TypeChecker {
return;
}

// check property
const type = this.getVariableType(ast.id, env);
ast.id.inferred = type;

if (type.type === 'model' || type.type === 'map') {
// { type: 'map', keyTypeName: 'string', valueTypeName: 'any' }
const currentPath = [ast.id.lexeme];
let current = type;
ast.propertyPathTypes = new Array(ast.propertyPath.length);
for (let i = 0; i < ast.propertyPath.length; i++) {
let prop = ast.propertyPath[i];
let find = this.getPropertyType(current, prop.lexeme);
if (!find) {
this.error(`The property ${prop.lexeme} is undefined ` +
`in model ${currentPath.join('.')}(${current.name})`, prop);
}
ast.propertyPathTypes[i] = find;
currentPath.push(prop.lexeme);
current = find;
}

return;
}

const name = ast.id.lexeme;
this.error(`The type of '${name}' must be model, object or map`, ast.id);
}
Expand Down Expand Up @@ -2045,7 +2057,7 @@ class TypeChecker {
return;
}

const aliasId = ast.aliasId.lexeme;
let aliasId = ast.aliasId.lexeme;
this.visitObject(ast.object, env);

for (let i = 0; i < ast.object.fields.length; i++) {
Expand All @@ -2058,18 +2070,20 @@ class TypeChecker {
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);
}
modelName = 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);
} else {
const checker = this.dependencies.get(aliasId);
expected = checker.getFieldType(modelField, modelName, aliasId);
expected = checker.getFieldType(modelField, modelName, moduleName);
}


Expand Down Expand Up @@ -2100,7 +2114,7 @@ class TypeChecker {
this.checkConstructModelFields(ast, model, `${modelId}`, env);
return;
}

if (builtin.has(aliasId)) {
const model = builtin.get(aliasId);
assert.ok(model.type === 'model');
Expand Down Expand Up @@ -2341,7 +2355,6 @@ class TypeChecker {
}

const name = id.lexeme;

if (env.local && env.local.hasDefined(name)) {
// 返回作用域链上定义的值
return env.local.get(name);
Expand Down Expand Up @@ -2376,13 +2389,13 @@ class TypeChecker {
if (isBasicType(type.valueType.name)) {
return _basic(type.valueType.name);
}
return this.getModel(type.valueType.name);
return this.getModel(type.valueType.name, type.valueType.moduleName);
}

if (type.type === 'model') {
let model, modelName;
let model, modelName, checker = this;
if (type.moduleName) {
const checker = this.dependencies.get(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)) {
Expand All @@ -2393,16 +2406,27 @@ class TypeChecker {
modelName = type.name;
}

const find = this.findProperty(model, propName, modelName);
const find = checker.findProperty(model, propName, modelName);
if (!find) {
return;
}

return this.getFieldType(find.modelField, find.modelName, type.moduleName);
const moduleName = find.moduleName || type.moduleName;
return this.getFieldType(find.modelField, find.modelName, moduleName);
}
}

calculatePropertyType(ast, env) {
const type = this.getVariableType(ast.id, env);
if (type.type === 'model' || type.type === 'map') {
let current = type;
for (let i = 0; i < ast.propertyPath.length; i++) {
let prop = ast.propertyPath[i];
current = this.getPropertyType(current, prop.lexeme);
}

return current;
}

if (this.enums.has(ast.id.lexeme)) {
return _enum(ast.id.lexeme);
Expand All @@ -2423,17 +2447,6 @@ class TypeChecker {
return _basic('class');
}

const type = this.getVariableType(ast.id, env);
if (type.type === 'model' || type.type === 'map') {
let current = type;
for (let i = 0; i < ast.propertyPath.length; i++) {
let prop = ast.propertyPath[i];
current = this.getPropertyType(current, prop.lexeme);
}

return current;
}

console.log(ast);
throw new Error('unknown type');
}
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/multi_catch/Darafile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"libraries": {
"OSS": "./oss.dara"
}
}
48 changes: 48 additions & 0 deletions test/fixtures/multi_catch/main.dara
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import './util.dara' Util;
import OSS;

static function call(size: number): void {
try{
if(size > 100) {
throw new Util.MainFileError{
name = 'name',
size = 100,
path = '100',
};
} else if (size == 100){
throw new Util.ExtendFileError{
code = 'name',
key2 = 'value2',
data = {
key1 = new OSS.File{
name = 'name',
path = '100',
}
}
};
} else {
throw new Util.ExtendSubFileError{
name = 'name',
data = {
name = '100'
},
};
}
} catch(err: Util.MainFileError) {
$Logger.info(err.name);
}catch(err: Util.ExtendFileError) {
$Logger.info(err.code);
$Logger.info(err.key2);
var data = err.data;
var key1234: OSS.File = data.key1;
$Logger.info(key1234.name);
$Logger.info(key1234.path);
}catch(err: Util.ExtendSubFileError) {
$Logger.info(err.name);
$Logger.info(err.data.name);
}catch(err: $Error) {
$Logger.info(err.message);
}catch(err) {
$Logger.info(err.message);
}
}
17 changes: 17 additions & 0 deletions test/fixtures/multi_catch/oss.dara
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

model File = {
name: string,
path: string,
};

exception FileError = {
code: string,
data: map[string]File
}

model SubFile = {
file: {
name: string,
}
}

Loading

0 comments on commit abf18dd

Please sign in to comment.