finished exercise
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
package ssw.mj.impl;
|
package ssw.mj.impl;
|
||||||
|
|
||||||
import javassist.bytecode.analysis.ControlFlow;
|
|
||||||
import javassist.compiler.ast.MethodDecl;
|
|
||||||
import ssw.mj.Errors;
|
|
||||||
import ssw.mj.Errors.Message;
|
import ssw.mj.Errors.Message;
|
||||||
import ssw.mj.scanner.Token;
|
import ssw.mj.scanner.Token;
|
||||||
|
import ssw.mj.symtab.Obj;
|
||||||
|
import ssw.mj.symtab.Struct;
|
||||||
|
|
||||||
import javax.xml.stream.FactoryConfigurationError;
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import static ssw.mj.Errors.Message.*;
|
import static ssw.mj.Errors.Message.*;
|
||||||
@@ -142,7 +140,7 @@ public final class Parser {
|
|||||||
static final EnumSet<Token.Kind> breakMethodDecl = EnumSet.of(rbrace, eof);
|
static final EnumSet<Token.Kind> breakMethodDecl = EnumSet.of(rbrace, eof);
|
||||||
|
|
||||||
|
|
||||||
static <T extends Enum<T>> EnumSet<T> enumUnion(EnumSet<T> first, EnumSet<T> ...sets) {
|
static <T extends Enum<T>> EnumSet<T> enumUnion(EnumSet<T> first, EnumSet<T>... sets) {
|
||||||
final var copy = EnumSet.copyOf(first);
|
final var copy = EnumSet.copyOf(first);
|
||||||
for (final var set : sets) {
|
for (final var set : sets) {
|
||||||
copy.addAll(set);
|
copy.addAll(set);
|
||||||
@@ -167,18 +165,25 @@ public final class Parser {
|
|||||||
check(Token.Kind.program);
|
check(Token.Kind.program);
|
||||||
check(Token.Kind.ident);
|
check(Token.Kind.ident);
|
||||||
|
|
||||||
|
final var program = tab.insert(Obj.Kind.Prog, t.val, Tab.noType);
|
||||||
|
tab.openScope();
|
||||||
|
|
||||||
while (!breakDecl.contains(sym)) {
|
while (!breakDecl.contains(sym)) {
|
||||||
if (firstVarDecl.contains(sym)) {
|
if (firstVarDecl.contains(sym)) {
|
||||||
VarDecl();
|
VarDecl();
|
||||||
} else if (firstClassDecl.contains(sym)) {
|
} else if (firstClassDecl.contains(sym)) {
|
||||||
ClassDecl();
|
ClassDecl();
|
||||||
} else if (firstConstDecl.contains(sym)){
|
} else if (firstConstDecl.contains(sym)) {
|
||||||
ConstDecl();
|
ConstDecl();
|
||||||
} else {
|
} else {
|
||||||
recoverDecl();
|
recoverDecl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tab.curScope.nVars() > MAX_GLOBALS) {
|
||||||
|
error(TOO_MANY_GLOBALS);
|
||||||
|
}
|
||||||
|
|
||||||
check(lbrace);
|
check(lbrace);
|
||||||
|
|
||||||
while (!breakMethodDecl.contains(sym)) {
|
while (!breakMethodDecl.contains(sym)) {
|
||||||
@@ -190,18 +195,33 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check(rbrace);
|
check(rbrace);
|
||||||
|
program.locals = tab.curScope.locals();
|
||||||
|
tab.closeScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConstDecl() {
|
private void ConstDecl() {
|
||||||
check(Token.Kind.final_);
|
check(Token.Kind.final_);
|
||||||
Type();
|
final var type = Type();
|
||||||
check(Token.Kind.ident);
|
check(Token.Kind.ident);
|
||||||
|
final var identVal = t.val;
|
||||||
check(Token.Kind.assign);
|
check(Token.Kind.assign);
|
||||||
|
|
||||||
if (sym == Token.Kind.number) {
|
if (sym == Token.Kind.number) {
|
||||||
|
if (type != Tab.intType) {
|
||||||
|
error(INCOMPATIBLE_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
scan();
|
scan();
|
||||||
|
final var obj = tab.insert(Obj.Kind.Con, identVal, type);
|
||||||
|
obj.val = t.numVal;
|
||||||
} else if (sym == Token.Kind.charConst) {
|
} else if (sym == Token.Kind.charConst) {
|
||||||
|
if (type != Tab.charType) {
|
||||||
|
error(INCOMPATIBLE_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
scan();
|
scan();
|
||||||
|
final var obj = tab.insert(Obj.Kind.Con, identVal, type);
|
||||||
|
obj.val = t.numVal;
|
||||||
} else {
|
} else {
|
||||||
error(TOKEN_EXPECTED, "number or character constant");
|
error(TOKEN_EXPECTED, "number or character constant");
|
||||||
}
|
}
|
||||||
@@ -210,12 +230,15 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void VarDecl() {
|
private void VarDecl() {
|
||||||
Type();
|
final var type = Type();
|
||||||
check(ident);
|
check(ident);
|
||||||
|
tab.insert(Obj.Kind.Var, t.val, type);
|
||||||
|
|
||||||
while (sym == Token.Kind.comma) {
|
while (sym == Token.Kind.comma) {
|
||||||
scan();
|
scan();
|
||||||
check(ident);
|
check(ident);
|
||||||
|
tab.insert(Obj.Kind.Var, t.val, type);
|
||||||
|
System.out.println(tab.curScope.nVars());
|
||||||
}
|
}
|
||||||
|
|
||||||
check(semicolon);
|
check(semicolon);
|
||||||
@@ -224,36 +247,81 @@ public final class Parser {
|
|||||||
private void ClassDecl() {
|
private void ClassDecl() {
|
||||||
check(class_);
|
check(class_);
|
||||||
check(ident);
|
check(ident);
|
||||||
|
final var identVal = t.val;
|
||||||
check(lbrace);
|
check(lbrace);
|
||||||
|
|
||||||
|
final var structObj = new Struct(Struct.Kind.Class);
|
||||||
|
tab.insert(Obj.Kind.Type, identVal, structObj);
|
||||||
|
|
||||||
|
tab.openScope();
|
||||||
|
|
||||||
while (firstVarDecl.contains(sym)) {
|
while (firstVarDecl.contains(sym)) {
|
||||||
VarDecl();
|
VarDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
structObj.fields = tab.curScope.locals();
|
||||||
|
|
||||||
|
if (tab.curScope.nVars() > MAX_FIELDS) {
|
||||||
|
error(TOO_MANY_FIELDS);
|
||||||
|
}
|
||||||
|
System.out.println(identVal);
|
||||||
|
tab.closeScope();
|
||||||
check(rbrace);
|
check(rbrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Type() {
|
private Struct Type() {
|
||||||
check(ident);
|
check(ident);
|
||||||
|
final var identVal = t.val;
|
||||||
|
var isArray = false;
|
||||||
|
|
||||||
if (sym == lbrack) {
|
if (sym == lbrack) {
|
||||||
|
isArray = true;
|
||||||
scan();
|
scan();
|
||||||
check(rbrack);
|
check(rbrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final var type = switch (identVal) {
|
||||||
|
case "int" -> Tab.intType;
|
||||||
|
case "char" -> Tab.charType;
|
||||||
|
default -> {
|
||||||
|
final var obj = tab.find(identVal);
|
||||||
|
|
||||||
|
if (obj == tab.noObj) {
|
||||||
|
error(NAME_NOT_FOUND, identVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.kind != Obj.Kind.Type) {
|
||||||
|
error(TYPE_EXPECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield obj.type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isArray) {
|
||||||
|
return new Struct(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MethodDecl() {
|
private void MethodDecl() {
|
||||||
|
var npars = 0;
|
||||||
|
Struct type = Tab.noType;
|
||||||
if (sym == ident) {
|
if (sym == ident) {
|
||||||
Type();
|
type = Type();
|
||||||
} else if (sym == void_) {
|
} else if (sym == void_) {
|
||||||
scan();
|
scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
check(ident);
|
check(ident);
|
||||||
|
final var methodObj = tab.insert(Obj.Kind.Meth, t.val, type);
|
||||||
check(lpar);
|
check(lpar);
|
||||||
|
|
||||||
|
tab.openScope();
|
||||||
|
|
||||||
if (sym == ident) {
|
if (sym == ident) {
|
||||||
FormPars();
|
npars = FormPars();
|
||||||
}
|
}
|
||||||
|
|
||||||
check(rpar);
|
check(rpar);
|
||||||
@@ -262,18 +330,41 @@ public final class Parser {
|
|||||||
VarDecl();
|
VarDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tab.curScope.nVars() > MAX_LOCALS) {
|
||||||
|
error(TOO_MANY_LOCALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodObj.name.equals("main") && methodObj.type != Tab.noType) {
|
||||||
|
error(MAIN_NOT_VOID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodObj.name.equals("main") && npars > 0) {
|
||||||
|
error(MAIN_WITH_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
Block();
|
Block();
|
||||||
|
|
||||||
|
methodObj.locals = tab.curScope.locals();
|
||||||
|
methodObj.nPars = npars;
|
||||||
|
tab.closeScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormPars() {
|
private int FormPars() {
|
||||||
Type();
|
var nPars = 0;
|
||||||
|
var type = Type();
|
||||||
check(ident);
|
check(ident);
|
||||||
|
tab.insert(Obj.Kind.Var, t.val, type);
|
||||||
|
nPars++;
|
||||||
|
|
||||||
while (sym == comma) {
|
while (sym == comma) {
|
||||||
scan();
|
scan();
|
||||||
Type();
|
type = Type();
|
||||||
check(ident);
|
check(ident);
|
||||||
|
tab.insert(Obj.Kind.Var, t.val, type);
|
||||||
|
nPars++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nPars;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Block() {
|
private void Block() {
|
||||||
@@ -322,7 +413,7 @@ public final class Parser {
|
|||||||
check(rpar);
|
check(rpar);
|
||||||
Statement();
|
Statement();
|
||||||
}
|
}
|
||||||
case break_-> {
|
case break_ -> {
|
||||||
scan();
|
scan();
|
||||||
check(semicolon);
|
check(semicolon);
|
||||||
}
|
}
|
||||||
@@ -358,17 +449,31 @@ public final class Parser {
|
|||||||
case lbrace -> Block();
|
case lbrace -> Block();
|
||||||
case semicolon -> scan();
|
case semicolon -> scan();
|
||||||
default -> recoverStatement();
|
default -> recoverStatement();
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Designator() {
|
private void Designator() {
|
||||||
check(ident);
|
check(ident);
|
||||||
|
|
||||||
|
final var targetObject = tab.find(t.val);
|
||||||
|
var lastType = targetObject.type;
|
||||||
|
|
||||||
|
if (targetObject == tab.noObj) {
|
||||||
|
error(NAME_NOT_FOUND, t.val);
|
||||||
|
}
|
||||||
|
|
||||||
while (sym == period || sym == lbrack) {
|
while (sym == period || sym == lbrack) {
|
||||||
if (sym == period) {
|
if (sym == period) {
|
||||||
scan();
|
scan();
|
||||||
check(ident);
|
check(ident);
|
||||||
|
final var fieldObject = tab.findField(t.val, lastType);
|
||||||
|
|
||||||
|
if (fieldObject == tab.noObj) {
|
||||||
|
error(FIELD_NOT_FOUND, t.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastType = fieldObject.type;
|
||||||
} else {
|
} else {
|
||||||
scan();
|
scan();
|
||||||
|
|
||||||
@@ -378,10 +483,11 @@ public final class Parser {
|
|||||||
|
|
||||||
Expr();
|
Expr();
|
||||||
|
|
||||||
|
lastType = lastType.elemType;
|
||||||
|
|
||||||
check(rbrack);
|
check(rbrack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssignOp() {
|
private void AssignOp() {
|
||||||
@@ -392,7 +498,8 @@ public final class Parser {
|
|||||||
case timesas -> scan();
|
case timesas -> scan();
|
||||||
case slashas -> scan();
|
case slashas -> scan();
|
||||||
case remas -> scan();
|
case remas -> scan();
|
||||||
default -> error(TOKEN_EXPECTED, "unexpected token. assignment token (=, +=, -=, *=, /=, %=), method call (\"(\"), increment (++) or decrement (--)");
|
default ->
|
||||||
|
error(TOKEN_EXPECTED, "unexpected token. assignment token (=, +=, -=, *=, /=, %=), method call (\"(\"), increment (++) or decrement (--)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +518,6 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ActPars() {
|
private void ActPars() {
|
||||||
|
|
||||||
check(lpar);
|
check(lpar);
|
||||||
|
|
||||||
if (sym == minus || firstFactor.contains(sym)) {
|
if (sym == minus || firstFactor.contains(sym)) {
|
||||||
@@ -446,20 +552,37 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Factor() {
|
private void Factor() {
|
||||||
switch(sym) {
|
switch (sym) {
|
||||||
case ident -> Designator();
|
case ident -> {
|
||||||
|
Designator();
|
||||||
|
|
||||||
|
if (sym == lpar) {
|
||||||
|
ActPars();
|
||||||
|
}
|
||||||
|
}
|
||||||
case number -> scan();
|
case number -> scan();
|
||||||
case charConst -> scan();
|
case charConst -> scan();
|
||||||
case new_ -> {
|
case new_ -> {
|
||||||
scan();
|
scan();
|
||||||
check(ident);
|
check(ident);
|
||||||
|
|
||||||
if (sym == lbrack) {
|
if (sym == lbrack) {
|
||||||
scan();
|
scan();
|
||||||
Expr();
|
Expr();
|
||||||
check(rbrack);
|
check(rbrack);
|
||||||
|
} else {
|
||||||
|
final var typeObj = tab.find(t.val);
|
||||||
|
|
||||||
|
if (typeObj == tab.noObj) {
|
||||||
|
error(NAME_NOT_FOUND, t.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeObj.type.kind != Struct.Kind.Class) {
|
||||||
|
error(CLASS_TYPE_EXPECTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case lpar -> {
|
case lpar -> {
|
||||||
scan();
|
scan();
|
||||||
Expr();
|
Expr();
|
||||||
check(rpar);
|
check(rpar);
|
||||||
|
|||||||
@@ -1,100 +1,143 @@
|
|||||||
package ssw.mj.impl;
|
package ssw.mj.impl;
|
||||||
|
|
||||||
|
import javassist.tools.rmi.StubGenerator;
|
||||||
|
import ssw.mj.Errors;
|
||||||
import ssw.mj.symtab.Obj;
|
import ssw.mj.symtab.Obj;
|
||||||
import ssw.mj.symtab.Scope;
|
import ssw.mj.symtab.Scope;
|
||||||
import ssw.mj.symtab.Struct;
|
import ssw.mj.symtab.Struct;
|
||||||
|
|
||||||
public final class Tab {
|
public final class Tab {
|
||||||
|
|
||||||
// Universe
|
// Universe
|
||||||
public static final Struct noType = new Struct(Struct.Kind.None);
|
public static final Struct noType = new Struct(Struct.Kind.None);
|
||||||
public static final Struct intType = new Struct(Struct.Kind.Int);
|
public static final Struct intType = new Struct(Struct.Kind.Int);
|
||||||
public static final Struct charType = new Struct(Struct.Kind.Char);
|
public static final Struct charType = new Struct(Struct.Kind.Char);
|
||||||
public static final Struct nullType = new Struct(Struct.Kind.Class);
|
public static final Struct nullType = new Struct(Struct.Kind.Class);
|
||||||
|
|
||||||
public final Obj noObj, chrObj;
|
public final Obj noObj, chrObj;
|
||||||
public Obj ordObj, lenObj;
|
public Obj ordObj, lenObj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only used for reporting errors.
|
* Only used for reporting errors.
|
||||||
*/
|
*/
|
||||||
private final Parser parser;
|
private final Parser parser;
|
||||||
/**
|
/**
|
||||||
* The current top scope.
|
* The current top scope.
|
||||||
*/
|
*/
|
||||||
public Scope curScope = null;
|
public Scope curScope = null;
|
||||||
// First scope opening (universe) will increase this to -1
|
// First scope opening (universe) will increase this to -1
|
||||||
/**
|
/**
|
||||||
* Nesting level of current scope.
|
* Nesting level of current scope.
|
||||||
*/
|
*/
|
||||||
private int curLevel = -2;
|
private int curLevel = -2;
|
||||||
|
|
||||||
public Tab(Parser p) {
|
public Tab(Parser p) {
|
||||||
parser = p;
|
parser = p;
|
||||||
|
|
||||||
// setting up "universe" (= predefined names)
|
// setting up "universe" (= predefined names)
|
||||||
// opening scope (curLevel goes to -1, which is the universe level)
|
// opening scope (curLevel goes to -1, which is the universe level)
|
||||||
openScope();
|
openScope();
|
||||||
|
|
||||||
noObj = new Obj(Obj.Kind.Var, "noObj", noType);
|
noObj = new Obj(Obj.Kind.Var, "noObj", noType);
|
||||||
|
|
||||||
insert(Obj.Kind.Type, "int", intType);
|
insert(Obj.Kind.Type, "int", intType);
|
||||||
insert(Obj.Kind.Type, "char", charType);
|
insert(Obj.Kind.Type, "char", charType);
|
||||||
insert(Obj.Kind.Con, "null", nullType);
|
insert(Obj.Kind.Con, "null", nullType);
|
||||||
|
|
||||||
chrObj = insert(Obj.Kind.Meth, "chr", charType);
|
chrObj = insert(Obj.Kind.Meth, "chr", charType);
|
||||||
openScope();
|
openScope();
|
||||||
Obj iVarObj = insert(Obj.Kind.Var, "i", intType);
|
Obj iVarObj = insert(Obj.Kind.Var, "i", intType);
|
||||||
iVarObj.level = 1;
|
iVarObj.level = 1;
|
||||||
chrObj.nPars = curScope.nVars();
|
chrObj.nPars = curScope.nVars();
|
||||||
chrObj.locals = curScope.locals();
|
chrObj.locals = curScope.locals();
|
||||||
closeScope();
|
closeScope();
|
||||||
|
|
||||||
// TODO Exercise UE-P-4: build "ord" universe method and store in ordObj
|
// TODO Exercise UE-P-4: build "ord" universe method and store in ordObj
|
||||||
|
|
||||||
// TODO Exercise UE-P-4: build "len" universe method and store in lenObj
|
ordObj = insert(Obj.Kind.Meth, "ord", intType);
|
||||||
|
openScope();
|
||||||
|
Obj chVarObj = insert(Obj.Kind.Var, "ch", charType);
|
||||||
|
chVarObj.level = 1;
|
||||||
|
ordObj.nPars = curScope.nVars();
|
||||||
|
ordObj.locals = curScope.locals();
|
||||||
|
closeScope();
|
||||||
|
|
||||||
// still on level -1
|
// TODO Exercise UE-P-4: build "len" universe method and store in lenObj
|
||||||
// now that the universe is constructed, the next node that will be added is the Program itself
|
|
||||||
// (which will open its own scope with level 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============================================
|
final var notypeArrStruct = new Struct(noType);
|
||||||
// TODO Exercise UE-P-4: implementation of symbol table
|
lenObj = insert(Obj.Kind.Meth, "len", intType);
|
||||||
// ===============================================
|
openScope();
|
||||||
|
Obj arrVarObj = insert(Obj.Kind.Var, "arr", notypeArrStruct);
|
||||||
|
arrVarObj.level = 1;
|
||||||
|
lenObj.nPars = curScope.nVars();
|
||||||
|
lenObj.locals = curScope.locals();
|
||||||
|
closeScope();
|
||||||
|
|
||||||
public void openScope() {
|
// still on level -1
|
||||||
curScope = new Scope(curScope);
|
// now that the universe is constructed, the next node that will be added is the Program itself
|
||||||
curLevel++;
|
// (which will open its own scope with level 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeScope() {
|
// ===============================================
|
||||||
curScope = curScope.outer();
|
// TODO Exercise UE-P-4: implementation of symbol table
|
||||||
curLevel--;
|
// ===============================================
|
||||||
}
|
|
||||||
|
|
||||||
public Obj insert(Obj.Kind kind, String name, Struct type) {
|
public void openScope() {
|
||||||
// TODO Exercise UE-P-4
|
curScope = new Scope(curScope);
|
||||||
return noObj;
|
curLevel++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void closeScope() {
|
||||||
* Retrieves the object with <code>name</code> from the innermost scope.
|
curScope = curScope.outer();
|
||||||
*/
|
curLevel--;
|
||||||
public Obj find(String name) {
|
}
|
||||||
// TODO Exercise UE-P-4
|
|
||||||
return noObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public Obj insert(Obj.Kind kind, String name, Struct type) {
|
||||||
* Retrieves the field <code>name</code> from the fields of
|
final var obj = new Obj(kind, name, type);
|
||||||
* <code>type</code>.
|
|
||||||
*/
|
|
||||||
public Obj findField(String name, Struct type) {
|
|
||||||
// TODO Exercise UE-P-4
|
|
||||||
return noObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============================================
|
if (kind == Obj.Kind.Var) {
|
||||||
// ===============================================
|
obj.adr = curScope.nVars();
|
||||||
|
obj.level = curLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
final var duplicate = curScope.locals().get(name);
|
||||||
|
|
||||||
|
if (duplicate != null) {
|
||||||
|
parser.error(Errors.Message.DUPLICATE_NAME_IN_SCOPE, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
curScope.insert(obj);
|
||||||
|
// TODO Exercise UE-P-4
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the object with <code>name</code> from the innermost scope.
|
||||||
|
*/
|
||||||
|
public Obj find(String name) {
|
||||||
|
// TODO Exercise UE-P-4
|
||||||
|
|
||||||
|
var scope = curScope;
|
||||||
|
|
||||||
|
while (scope != null) {
|
||||||
|
final var result = scope.locals().get(name);
|
||||||
|
if (result != null) return result;
|
||||||
|
scope = scope.outer();
|
||||||
|
}
|
||||||
|
|
||||||
|
return noObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the field <code>name</code> from the fields of
|
||||||
|
* <code>type</code>.
|
||||||
|
*/
|
||||||
|
public Obj findField(String name, Struct type) {
|
||||||
|
// TODO Exercise UE-P-5
|
||||||
|
final var fieldObject = type.findField(name);
|
||||||
|
return fieldObject == null ? noObj : fieldObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// ===============================================
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user