diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..62ff3680 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,83 @@ +name: Tests + +on: [push, pull_request] + +jobs: + lexer: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=lexer + + parser: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=parser + + semantic: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=semantic + + codegen: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Install spim + run: sudo apt-get install spim + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=codegen diff --git a/Readme.md b/Readme.md index 4b475a39..55093d31 100644 --- a/Readme.md +++ b/Readme.md @@ -106,10 +106,14 @@ En este proyecto se realizarán entregas parciales a lo largo del curso. Para re ### 2. Asegúrese de tener la siguiente configuración antes de hacer click en **Create pull request**. - **base repository**: `matcom/cool-compiler-2020` (repositorio original) + - **branch**: `entrega-final` - **head repository**: `/cool-compiler-2020` (repositorio propio) + - **branch**: `master` (o la que corresponda) > Asegúrese que se indica **Able to merge**. De lo contrario, existen cambios en el repositorio original que usted no tiene, y debe actualizarlos. +> **NOTA**: Asegúrese que el _pull request_ se hace a la rama `entrega-final`. + ![](img/img6.png) ### 3. Introduzca un título y descripción adecuados, y haga click en **Create pull request**. diff --git a/img/img1.png b/img/img1.png index 7b6186cc..ccb88735 100644 Binary files a/img/img1.png and b/img/img1.png differ diff --git a/img/img10.png b/img/img10.png index 1b528280..4808caa7 100644 Binary files a/img/img10.png and b/img/img10.png differ diff --git a/img/img11.png b/img/img11.png index d7c02494..b1934ce7 100644 Binary files a/img/img11.png and b/img/img11.png differ diff --git a/img/img12.png b/img/img12.png index d38a626b..44c13253 100644 Binary files a/img/img12.png and b/img/img12.png differ diff --git a/img/img2.png b/img/img2.png index 17e1177c..8072ab3d 100644 Binary files a/img/img2.png and b/img/img2.png differ diff --git a/img/img3.png b/img/img3.png index 864d620b..d0df59cf 100644 Binary files a/img/img3.png and b/img/img3.png differ diff --git a/img/img4.png b/img/img4.png index d5a194a7..231daff3 100644 Binary files a/img/img4.png and b/img/img4.png differ diff --git a/img/img5.png b/img/img5.png index 5fdc0e65..c40009a0 100644 Binary files a/img/img5.png and b/img/img5.png differ diff --git a/img/img6.png b/img/img6.png index a3ade1b0..7cd8ad2c 100644 Binary files a/img/img6.png and b/img/img6.png differ diff --git a/img/img7.png b/img/img7.png index 665342b7..511c8ea6 100644 Binary files a/img/img7.png and b/img/img7.png differ diff --git a/img/img8.png b/img/img8.png index aad895da..54b34a91 100644 Binary files a/img/img8.png and b/img/img8.png differ diff --git a/img/img9.png b/img/img9.png index f7a8f45e..fa093225 100644 Binary files a/img/img9.png and b/img/img9.png differ diff --git a/requirements.txt b/requirements.txt index 9eb0cad1..cba16ee2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pytest pytest-ordering +ply diff --git a/src/AST.py b/src/AST.py new file mode 100644 index 00000000..b126157e --- /dev/null +++ b/src/AST.py @@ -0,0 +1,193 @@ +class Node: + line = 0 + index = 0 + +class Program(Node): + def __init__(self, classes = None): + self.classes = classes + if classes is None: + self.classes = [] + +class Class(Node): + def __init__(self, _type, inherit, features=None): + self.name = _type + self.inherit = inherit + self.methods = [] + self.attributes = [] + + if features is not None: + for feature in features: + if isinstance(feature, Method): + self.methods.append(feature) + else: + self.attributes.append(feature) + +class Type: + def __init__(self, type): + self.name = type + +class Branch: + def __init__(self, _var, _expr): + self.var = _var + self.expr = _expr + +class Feature(Node): + pass + +class Method(Feature): + def __init__(self, id, parameters, return_type, expr=None): + self.id = id + self.parameters = parameters + self.return_type = return_type + self.expression = expr + +class Attribute(Feature): + def __init__(self, id, _type, _expr = None): + self.type = _type + self.expr = _expr + self.id = id + +class Expression(Node): + pass + +class Atom(Expression): + pass + +class Assign(Expression): + def __init__(self, _id, expr): + self.id = _id + self.expression = expr + +class Dispatch(Atom): + def __init__(self, func_id, params = None, left_expr = None): + self.left_expression = left_expr + self.func_id = func_id + self.parameters = params + self.className = 'dispatch' + + if params is None: + self.parameters = [] + +class StaticDispatch(Atom): + def __init__(self, func_id, params, left_expr, parent_type): + self.left_expression = left_expr + self.func_id = func_id + self.parameters = params + self.parent_type = parent_type + self.className = 'dispatch' + +class Conditional(Atom): + def __init__(self, if_expr, then_expr, else_expr): + self.if_expression = if_expr + self.then_expression = then_expr + self.else_expression = else_expr + self.className = 'conditional' + +class Loop(Atom): + def __init__(self, while_expr, loop_exprs): + self.while_expression = while_expr + self.loop_expression = loop_exprs + self.className = 'loop' + +class LetVar(Atom): + def __init__(self, declarations, in_expr): + self.in_expression = in_expr + self.declarations = declarations + +class Var(Atom): + def __init__(self, _name, _type): + self.id = _name + self.type = _type + +class Case(Atom): + def __init__(self, case_expr, implications): + self.case_expression = case_expr + self.implications = implications + self.className = 'case' + +class NewType(Atom): + def __init__(self, _type_name): + self.type_name = _type_name + +class UnaryOperator(Expression): + def __init__(self,expr): + self.expression = expr + +class BinaryOperator(Expression): + def __init__(self, left_expr, right_expr): + self.left_expression = left_expr + self.right_expression = right_expr + +class BAritmeticOperation(BinaryOperator): + pass + +class Plus(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "+" + self.first = _first + self.second = _second + +class Minus(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "-" + self.first = _first + self.second = _second + +class Star(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "*" + self.first = _first + self.second = _second + +class Div(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "/" + self.first = _first + self.second = _second + +class Not(UnaryOperator): + def __init__(self, _expr): + self.expr = _expr + +class IntegerComplement(Atom): + def __init__(self, _expr): + self.expression = _expr + +class IsVoid(UnaryOperator): + def __init__(self, _expr): + self.expression = _expr + +class LowerThan(BinaryOperator): + def __init__(self, _first, _second): + self.symbol = "<" + self.first = _first + self.second = _second + +class LowerEqualThan(BinaryOperator): + def __init__(self, _first, _second): + self.symbol = "<=" + self.first = _first + self.second = _second + +class EqualThan(BinaryOperator): + def __init__(self, _first, _second): + self.symbol = "=" + self.first = _first + self.second = _second + +class Block(Atom): + def __init__(self, exprs): + self.expressions = exprs + self.className = 'block' + +class Interger(Atom): + def __init__(self,value): + self.value = value + +class String(Atom): + def __init__(self, value): + self.value = value + +class Boolean(Atom): + def __init__(self,value): + self.value = value \ No newline at end of file diff --git a/src/AST_CIL.py b/src/AST_CIL.py new file mode 100644 index 00000000..3f14ad71 --- /dev/null +++ b/src/AST_CIL.py @@ -0,0 +1,248 @@ +class Node: + pass + +class Program(Node): + def __init__(self): + self.type_section = [] + self.data_section = {} #data[string] = tag + self.code_section = [] + +class Type(Node): + def __init__(self, name): + self.name = name + self.attributes = [] + self.methods = {} + def to_string(self): + return "type {} \n attributes {}\n methods {}\n".format(self.name, self.attributes, self.methods) + +class Data(Node): + def __init__(self, vname, value): + self.vname = vname + self.value = value + +class Function(Node): + def __init__(self, fname): + self.fname = fname + self.params = [] + self.localvars = [] + self.instructions = [] + + +# class Param(Node): +# def __init__(self, vinfo): +# self.vinfo = vinfo +# def to_string(self): +# return "PARAM {}".format(self.vinfo) + +# class Local(Node): +# def __init__(self, vinfo): +# self.vinfo = vinfo +# def to_string(self): +# return "LOCAL {}".format(self.vinfo) + + +class Instruction(Node): + pass + +class Assign(Instruction): + def __init__(self, dest, source): + self.dest = dest + self.source = source + def to_string(self): + return "ASSIGN {} {}\n".format(self.dest, self.source) + +class Arithmetic(Instruction): + pass + +class Plus(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} + {}".format(self.dest, self.left, self.right) + +class Minus(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} - {}".format(self.dest, self.left, self.right) + +class Star(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} * {}".format(self.dest, self.left, self.right) + +class Div(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} / {}".format(self.dest, self.left, self.right) + +class GetAttrib(Instruction): + def __init__(self, dest, instance, attribute): + self.dest = dest + self.instance = instance + self.attribute = attribute + def to_string(self): + return "{} = GETATTR {} {}".format(self.dest, self.instance, self.attribute) + +class SetAttrib(Instruction): + def __init__(self, instance, attribute, src): + self.instance = instance + self.attribute = attribute + self.src = src + def to_string(self): + return "SETATTR {} {} {}".format(self.instance, self.attribute, self.src) + +class Allocate(Instruction): + def __init__(self, dest, ttype): + self.dest = dest + self.ttype = ttype + + def to_string(self): + return "{} = ALLOCATE {}".format(self.dest, self.ttype) + +class Array(Instruction): + def __init__(self, dest, src): + self.dest = dest + self.src = src + +class TypeOf(Instruction): + def __init__(self, dest, var): + self.dest = dest + self.var = var + def to_string(self): + return "{} = TYPEOF {}".format(self.dest, self.var) + +class Label(Instruction): + def __init__(self, name): + self.name = name + + def to_string(self): + return "LABEL {}".format(self.name) + +class Goto(Instruction): + def __init__(self, name): + self.name = name + + def to_string(self): + return "GOTO {}".format(self.name) + +class GotoIf(Instruction): + def __init__(self, condition, label): + self.condition = condition + self.label = label + def to_string(self): + return "IF {} GOTO {}".format(self.condition, self.label) + +class Call(Instruction): + def __init__(self, dest, func): + self.dest = dest + self.func = func + + def to_string(self): + return "{} = CALL {}".format(self.dest, self.func) + +class VCall(Instruction): + def __init__(self, dest, ttype, func): + self.dest = dest + self.ttype = ttype + self.func = func + def to_string(self): + return "{} = VCALL {} {}".format(self.dest, self.ttype, self.func) + +class Arg(Instruction): + def __init__(self, vinfo): + self.vinfo = vinfo + def to_string(self): + return "ARG {}".format(self.vinfo) + +class Return(Instruction): + def __init__(self, value=None): + self.value = value + + def to_string(self): + return "RETURN {}".format(self.value) + +class Load(Instruction): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + def to_string(self): + return "{} = LOAD {}".format(self.dest, self.msg) + +class Length(Instruction): + def __init__(self, dest, str_addr): + self.dest = dest + self.str_addr = str_addr + def to_string(self): + return "{} = LENGTH {}".format(self.dest, self.str_addr) + +class Concat(Instruction): + def __init__(self, dest, head, tail): + self.dest = dest + self.head = head + self.tail = tail + + def to_string(self): + return "{} = CONCAT {} {}".format(self.dest, self.head, self.tail) + +class Prefix(Instruction): + def __init__(self, dest, str_addr, pos): + self.dest = dest + self.str_addr = str_addr + self.pos = pos + +class Substring(Instruction): + def __init__(self, dest, str_addr, pos): + self.dest = dest + self.str_addr = str_addr + self.pos = pos + +class ToStr(Instruction): + def __init__(self, dest, ivalue): + self.dest = dest + self.ivalue = ivalue + +class Read(Instruction): + def __init__(self, dest): + self.dest = dest + +class Print(Instruction): + def __init__(self, str_addr): + self.str_addr = str_addr + def to_string(self): + return "PRINT {}".format(self.str_addr) + +class IsVoid(Instruction): + def __init__(self, dest, obj): + self.dest = dest + self.obj = obj + +class LowerThan(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr + +class LowerEqualThan(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr + +class EqualThan(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr + +class EqualStrThanStr(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr \ No newline at end of file diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py new file mode 100644 index 00000000..c1955137 --- /dev/null +++ b/src/cil_to_mips.py @@ -0,0 +1,103 @@ +from AST_CIL import * +import visitor + +class Build_Mips: + def __init__(self, ast): + self.lines = [] + self.current_function = None + self.visit(ast) + + def add(self, line): + self.lines.append(line) + + def stack_pos(self, name): + temp = self.current_function.params + self.current_function.localvars + index = 4*temp.index(name) + return -index + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(Program) + def visit(self, program): + + self.add('.data') + for _str, tag in program.data_section.items(): + self.add(tag + ':' + ' .asciiz ' + _str) + self.add('.text') + self.add('main:') + self.add('addiu $a0, $zero, 1') + self.add('jal function_Main_main') + self.add('li $v0, 10') #exit() + self.add('syscall') + for f in program.code_section: + self.visit(f) + + @visitor.when(Function) + def visit(self, function): + #ya se pusieron los argumentos en la pila + self.current_function = function + self.add(function.fname + ':') + + #ya se guardaron los argumentos en la pila + #tenemos que guardar espacio para las variables locales + + line = 'addi $sp, $sp, -' + str(4*len(function.localvars)) #espacio para las variables locales + self.add(line) + + self.add('addi $sp, $sp, -8') # adjust stack for 2 item + self.add('sw $ra, 4($sp)') # save return address + self.add('sw $fp, 0($sp)') # save old frame pointer + + n = 4*(len(function.params) + len(function.localvars) + 1) + self.add('addi $fp, $sp, {}'.format(n)) # fp apunta al primer argumento + + for intr in function.instructions: + self.visit(intr) + + #restaurar los valores de los registros + #poner el frame pointer donde estaba + + self.add('lw $ra, 4($sp)')#restauro direccion de retorno + self.add('lw $t1, 0($sp)') + self.add('addi $sp, $fp, 4') + self.add('move $fp, $t1') + + self.add('jr $ra') # and return + self.current_function = None + + @visitor.when(Arg) + def visit(self, arg): + self.add('addi $sp, $sp, -4') # adjust stack for 1 item + #localizar el valor de arg en las variables locales + index = self.stack_pos(arg.vinfo) + #pasarlo a un registro + self.add('lw $t1, {}($fp)'.format(index)) + self.add('sw $t1, 0($sp)') # save argument for next function + + @visitor.when(Call) + def visit(self, call): + #ya se pusieron los argumentos en la pila + self.add('jal ' + call.func) + index = self.stack_pos(call.dest) + self.add('sw $v0, {}($fp)'.format(index)) + + @visitor.when(Load) + def visit(self, load): + index = self.stack_pos(load.dest) + self.add('la $t1, {}'.format(load.msg)) + self.add('sw $t1, {}($fp)'.format(index)) + + @visitor.when(Print) + def visit(self, _print): + self.add('li $v0, 4') # system call code for print_str + index = self.stack_pos(_print.str_addr) #pos en la pila + self.add('lw $a0, {}($fp)'.format(index)) # str to print + self.add('syscall') # print it + + @visitor.when(Return) + def visit(self, ret): + index = self.stack_pos(ret.value) + self.add('lw $t1, {}($fp)'.format(index)) + self.add('move $v0, $t1') diff --git a/src/codegenTest.py b/src/codegenTest.py new file mode 100644 index 00000000..90b9d1e5 --- /dev/null +++ b/src/codegenTest.py @@ -0,0 +1,36 @@ +import lexer_rules +import parser_rules +import sys + +from ply.lex import lex +from ply.yacc import yacc +from semantic_rules import Semantic +import cool_to_cil, cil_to_mips + +def run(addr): + lexer = lex(module=lexer_rules) + parser = yacc(module=parser_rules) + sem = Semantic() + + with open(addr, encoding = "utf-8") as f: + text = f.read() + + ast = parser.parse(text, lexer) + sem.visit(ast) + + cil = cool_to_cil.Build_CIL(ast, sem) + + mips = cil_to_mips.Build_Mips(cil.astCIL) + + out_file = addr.split(".") + out_file[-1] = "mips" + out_file = ".".join(out_file) + + mips_code = '' + for line in mips.lines: + mips_code += line + '\n' + + with open(out_file, 'w') as f: + f.write(mips_code) + f.close() + exit(0) diff --git a/src/compiling.py b/src/compiling.py new file mode 100644 index 00000000..c0569e50 --- /dev/null +++ b/src/compiling.py @@ -0,0 +1,9 @@ +import sys, lexerTest, parserTest, semanticTest, codegenTest + +addr = None +addr = sys.argv[1] + +lexerTest.run(addr) +parserTest.run(addr) +semanticTest.run(addr) +codegenTest.run(addr) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py new file mode 100644 index 00000000..b3bf78c7 --- /dev/null +++ b/src/cool_to_cil.py @@ -0,0 +1,140 @@ +import visitor as visitor +from AST import * +import AST_CIL + +class Build_CIL: + def __init__(self, ast, sem): + self.end_line = {} + self.idCount = 0 + self.astCIL = AST_CIL.Program() + self.local_variables = [Var('self', 'SELF_TYPE')] + self.local_variables_map = [(0,0)] + self.local_variables_original = {} + self.local_variables_name = {} + self.constructor = {} + self.classmethods = {} + self.BFS(sem.graph, sem.classmethods_original) + self.visit(ast, self.astCIL) + + def BFS(self, graph, class_methods): + self.classmethods[('Object', 'abort')] = 'function_Object_abort' + self.classmethods[('Object', 'type_name')] = 'function_Object_type_name' + self.classmethods[('Object', 'copy')] = 'function_Object_copy' + self.classmethods[('IO', 'out_string')] = 'function_IO_out_string' + self.classmethods[('IO', 'out_int')] = 'function_IO_out_int' + self.classmethods[('IO', 'in_string')] = 'function_IO_in_string' + self.classmethods[('IO', 'in_int')] = 'function_IO_in_int' + self.classmethods[('String', 'length')] = 'function_String_length' + self.classmethods[('String', 'concat')] = 'function_String_concat' + self.classmethods[('String', 'substr')] = 'function_String_substr' + + l = ['Object'] + while len(l) > 0: + temp = l.pop(0) + if not graph.__contains__(temp): continue + for _class in graph[temp]: + l.append(_class) + for function in class_methods[temp]: + self.classmethods[(_class, function)] = self.classmethods[(temp, function)] + + + def get_local(self): + dest = 'local_' + str(self.idCount) + self.idCount += 1 + return dest + + @visitor.on('node') + def visit(self, node, nodeCIL): + pass + + @visitor.when(Program) + def visit(self, program, programCIL): + + #añadir IO, Object, Int, String, Bool + _type_IO = AST_CIL.Type('IO') + func = 'function' + '_' + 'IO' + '_' + 'out_string' + _type_IO.methods['out_string'] = func + self.classmethods[('IO', 'out_string')] = func + f = AST_CIL.Function(func) + f.params.append('x') + f.instructions.append(AST_CIL.Print('x')) + self.astCIL.code_section.append(f) + programCIL.type_section.append(_type_IO) + + for c in program.classes: + self.visit(c, programCIL) + + @visitor.when(Class) + def visit(self, _class, programCIL): + #clase que estoy visitando + self.current_class = _class.name + + #crear el tipo correspondiente + _type = AST_CIL.Type(_class.name) + #annadir el codigo de la clase + for m in _class.methods: + self.visit(m, _type) + + programCIL.type_section.append(_type) + self.current_class = None + + @visitor.when(Method) + def visit(self, method, typeCIL): + + self.current_method = method.id + + func = 'function' + '_' + self.current_class + '_' + method.id + typeCIL.methods[method.id] = func + + self.classmethods[(self.current_class, method.id)] = func + + f = AST_CIL.Function(func) + + for arg in method.parameters: + f.params.append(arg.id) + + result = self.visit(method.expression, f) + f.instructions.append(AST_CIL.Return(result)) + + self.astCIL.code_section.append(f) + + self.local_variables.clear() + self.local_variables_map.clear() + self.local_variables.append(Var('self','SELF_TYPE')) + self.local_variables_map.append((0,0)) + self.current_method = None + + @visitor.when(String) + def visit(self, string, functionCIL): + #crear tag + #annadir a data + tag = 's' + str(len(self.astCIL.data_section)) + + n = len(string.value) + + if string.value[n-1] == '\n': + s = string.value.replace("\n",'\\n\"') + s = '\"' + s + else: s = '"' + s + '"' + + self.astCIL.data_section[s] = tag + d = self.get_local() + intr = AST_CIL.Load(d, tag) + functionCIL.localvars.append(d) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Dispatch) + def visit(self, dispatch, functionCIL): + dest = 'local_' + str(self.idCount) + self.idCount += 1 + + for item in dispatch.parameters: #e(e1,e2,...,en) + result = self.visit(item, functionCIL) + functionCIL.instructions.append(AST_CIL.Arg(result)) + + intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) + functionCIL.localvars.append(dest) + functionCIL.instructions.append(intr) + + return dest diff --git a/src/coolc.sh b/src/coolc.sh old mode 100755 new mode 100644 index 3088de4f..9e9c30b4 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,9 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "Lexer and Parser" # TODO: Recuerde cambiar estas +echo "Carlos Martinez Molina y Eziel Ramos Pinon" # TODO: líneas a los valores correctos # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +#echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +python compiling.py ${INPUT_FILE} ${OUTPUT_FILE} \ No newline at end of file diff --git a/src/lexerTest.py b/src/lexerTest.py new file mode 100644 index 00000000..162bc8fd --- /dev/null +++ b/src/lexerTest.py @@ -0,0 +1,46 @@ +import lexer_rules +from ply.lex import lex +import sys + +def run(addr): + lexer = lex(module=lexer_rules) + with open(addr, encoding = "utf-8") as f: + text = f.read() + + lexer.input(text) + token = lexer.token() + + while token is not None: + try: + token = lexer.token() + except(): + lexer.skip(1) + + # temp = lexer_rules.result.split(':') + # s = temp[0] + # lexer_rules.result = '' + # return s + + if lexer_rules.my_bool: + print(lexer_rules.result + '\n') + lexer_rules.result = '' + lexer_rules.my_bool = False + exit(1) + +# run('C:/Users/acast/Documents/GitHub/cool-compiler-2020/tests/lexer/comment1.cl') + +# text = "" +# lexer = lex(module=lexer_rules) +# fpath = "C:/Users/Eziel/Downloads/Telegram Desktop/cool-compiler-2020/tests/" +# fpath += "parser/" +# fpath += "assignment1" +# fpath += ".cl" +# with open(fpath, encoding = "utf-8") as file: +# text = file.read() +# lexer.input(text) + +# token = lexer.token() + +# while token is not None: +# print(token) +# token = lexer.token() \ No newline at end of file diff --git a/src/lexer_rules.py b/src/lexer_rules.py new file mode 100644 index 00000000..140718bc --- /dev/null +++ b/src/lexer_rules.py @@ -0,0 +1,270 @@ +from ply.lex import TOKEN +my_bool = False +result = '' + +tokens = [ +# Identifiers +'ID', 'TYPE', + +# Primitive Types +'INTEGER', 'STRING', 'TRUE', 'FALSE', + +# Literals +'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'TDOTS', 'COMMA', 'DOT', 'SEMICOLON', 'AT', + +# Operators +'PLUS', 'MINUS', 'MULTIPLY', 'DIVIDE', 'EQ', 'LT', 'LTEQ', 'ASSIGN', 'INT_COMP', + +# Special Operators +'ARROW', + +# reserved_keywords +'CASE', 'CLASS', 'ELSE', 'ESAC', 'FI', 'IF', 'IN', 'INHERITS', 'ISVOID', "LET", +"LOOP", "NEW", "OF", "POOL", "THEN", "WHILE", "NOT" + +] + +reserved_keywords = { + "case": "CASE", + + "class": "CLASS", + #"Class": "CLASS", + #"CLaSS": "CLASS", + + #"eLSe": "ELSE", + "else": "ELSE", + #"elsE": "ELSE", + #"ElsE": "ELSE", + + "esac": "ESAC", + + "fi": "FI", + #"Fi": "FI", + #"fI": "FI", + + "if": "IF", + #"If": "IF", + #"iF": "IF", + + "in": "IN", + + "inherits": "INHERITS", + #"iNHeRiTS": "INHERITS", + + "isvoid": "ISVOID", + "let": "LET", + "loop": "LOOP", + "new": "NEW", + "of": "OF", + "pool": "POOL", + + "then": "THEN", + #"THeN": "THEN", + #"tHen": "THEN", + + "while": "WHILE", + "not": "NOT", + "true":"TRUE", + "false":"FALSE" + } + +reserved = reserved_keywords.keys() # ply reserved keywords map + + +# Simple tokens +t_LPAREN = r'\(' # ( +t_RPAREN = r'\)' # ) +t_LBRACE = r'\{' # { +t_RBRACE = r'\}' # } +t_TDOTS = r'\:' # : +t_COMMA = r'\,' # , +t_DOT = r'\.' # . +t_SEMICOLON = r'\;' # ; +t_AT = r'\@' # @ +t_MULTIPLY = r'\*' # * +t_DIVIDE = r'\/' # / +t_PLUS = r'\+' # + +t_MINUS = r'\-' # - +t_INT_COMP = r'~' # ~ +t_LT = r'\<' # < +t_EQ = r'\=' # = +t_LTEQ = r'\<\=' # <= +t_ASSIGN = r'\<\-' # <- +t_ARROW = r'\=\>' # => + +t_ignore_WHITESPACES = r"[ \t]+" + +def find_column(t): + line_start = t.lexer.lexdata.rfind('\n', 0, t.lexpos) + 1 + return t.lexpos - line_start + 1 + +@TOKEN(r"\d+") +def t_INTEGER(token): + token.value = int(token.value) + return token + +@TOKEN(r"[A-Z][a-zA-Z_0-9]*") +def t_TYPE(token): + tempL = str.lower(token.value) + if reserved_keywords.keys().__contains__(tempL): + token.value = tempL + token.type = reserved_keywords.get(token.value, 'TYPE') + return token + +@TOKEN(r"[a-z][a-zA-Z_0-9]*") +def t_ID(token): + tempL = str.lower(token.value) + if reserved_keywords.keys().__contains__(tempL): + token.value = tempL + token.type = reserved_keywords.get(token.value, 'ID') + return token + +def t_NEWLINE(token): + r"\n+" + token.lexer.lineno += len(token.value) + +# LEXER STATES +def states(): + return ( + ("STRING", "exclusive"), + ("COMMENT", "exclusive") + ) +states = states() + + +# THE STRING STATE +@TOKEN(r"\"") +def t_start_string(token): + token.lexer.push_state("STRING") + token.lexer.string_backslashed = False + token.lexer.stringbuf = "" + + +@TOKEN(r"\n") +def t_STRING_newline(token): + global my_bool + global result + token.lexer.lineno += 1 + if not token.lexer.string_backslashed: + token.lexer.skip(1) + token.lexer.pop_state() + #print(f'({token.lineno}, {find_column(token)}) - LexicographicError: Unterminated string constant') + if result == '': + result = f'({token.lineno}, {find_column(token)}) - LexicographicError: Unterminated string constant' + my_bool = True + else: + token.lexer.string_backslashed = False + +@TOKEN(r"\"") +def t_STRING_end(token): + if not token.lexer.string_backslashed: + token.lexer.pop_state() + token.value = token.lexer.stringbuf + token.type = "STRING" + return token + else: + token.lexer.stringbuf += '"' + token.lexer.string_backslashed = False + +@TOKEN('\0') +def t_STRING_null(t): + global my_bool + global result + #print(f'({t.lexer.lineno}, {find_column(t)}) - LexicographicError: String contains null character') + if result=='': + result = f'({t.lexer.lineno}, {find_column(t)}) - LexicographicError: String contains null character' + my_bool = True + +@TOKEN(r"[^\n]") +def t_STRING_anything(token): + if token.lexer.string_backslashed: + if token.value == 'b': + token.lexer.stringbuf += '\b' + elif token.value == 't': + token.lexer.stringbuf += '\t' + elif token.value == 'n': + token.lexer.stringbuf += '\n' + elif token.value == 'f': + token.lexer.stringbuf += '\f' + elif token.value == '\\': + token.lexer.stringbuf += '\\' + else: + token.lexer.stringbuf += token.value + token.lexer.string_backslashed = False + else: + if token.value != '\\': + token.lexer.stringbuf += token.value + else: + token.lexer.string_backslashed = True + +# STRING ignored characters +t_STRING_ignore = '' + +def t_STRING_eof(t): + global my_bool + global result + #print(f'({t.lineno}, {find_column(t)}) - LexicographicError: EOF in string constant') + if result=='': + result = f'({t.lineno}, {find_column(t)}) - LexicographicError: EOF in string constant' + my_bool = True + +# STRING error handler +def t_STRING_error(token): + global my_bool + global result + if result == '': + result = "Illegal character! Line: {0}, character: {1}".format(token.lineno, token.value[0]) + #print("Illegal character! Line: {0}, character: {1}".format(token.lineno, token.value[0])) + token.lexer.skip(1) + my_bool = True + + +# THE COMMENT STATE +@TOKEN(r"\(\*") +def t_start_comment(token): + token.lexer.push_state("COMMENT") + token.lexer.comment_count = 0 + +@TOKEN(r"\(\*") +def t_COMMENT_startanother(t): + t.lexer.comment_count += 1 + +@TOKEN(r"\n") +def t_COMMENT_NEWLINE(t): + t.lexer.lineno+=1 + +def t_COMMENT_eof(t): + global my_bool + global result + #print(f"({t.lineno}, {find_column(t)}) - LexicographicError: EOF in comment") + if result=='': + result = f"({t.lineno}, {find_column(t)}) - LexicographicError: EOF in comment" + my_bool = True + +@TOKEN(r"\*\)") +def t_COMMENT_end(token): + if token.lexer.comment_count == 0: + token.lexer.pop_state() + else: + token.lexer.comment_count -= 1 + +# COMMENT ignored characters +t_COMMENT_ignore = '' +t_ignore_COMMENT_LINE = r'\-\-[^\n]*' +t_ignore = ' \t\r\f' + +# COMMENT error handler +def t_COMMENT_error(t): + t.lexer.skip(1) + +def t_error(t): + global my_bool + global result + message = f'({t.lineno}, {find_column(t)}) - LexicographicError: ERROR "' + message += t.value[0] + message +='"' + #print(message) + if result =='': + result = message + t.lexer.skip(1) + my_bool = True \ No newline at end of file diff --git a/src/mips/newObjects.asm b/src/mips/newObjects.asm new file mode 100644 index 00000000..c13e0c8a --- /dev/null +++ b/src/mips/newObjects.asm @@ -0,0 +1,59 @@ +#class ListNode { +# int data; +# ListNode next; +# +# ListNode(int data) { +# this.data = data; +# next = null; +# } +# ... +# next = new ListNode(data); +# ... +#} + +j target + + +newListNode: +#...not shown: save registers +li $a0, 3 +move $s0, $a0 #s0=data + +addiu $a0, $zero, 8 #call sbrk(sizeof(ListNode)) + +#jal sbrk # i.e.,sbrk(8) +li $v0, 9 #set syscall code for sbrk +syscall + +addu $s1,$zero,$v0 #s1=this +sw $s0,0($s1) #this.data = data +addu $t0,$zero,$zero#$t0 <-- null (0) +sw $t0, 4($s1) #this.next = null\\memory[$s1+4] <-- null +addu $v0, $zero, $s1 #return this +#...not shown: restore registers +jr $ra #return #regreso a: --> jal function + + + +target: +jal newListNode #ejecuto la funcion y retorno a este punto + +la $t1,($v0) #copiar direccion +lw $a0, 0($t1) #interger to print || $v0 contiene la direccion del new object +li $v0, 1 # system call code for print_int +syscall # print it + + +#imprimir $v0 +#imprimir memory[$v0+4] +#lw $a0, 0($v0) #interger to print || $v0 contiene la direccion del new object +#li $v0, 1 # system call code for print_int +#syscall # print it + + + + +#exit() +li $v0, 10 # Systemcall code exit +syscall + diff --git a/src/mips/print_int.asm b/src/mips/print_int.asm new file mode 100644 index 00000000..93ffde80 --- /dev/null +++ b/src/mips/print_int.asm @@ -0,0 +1,7 @@ +li $v0, 1 # system call code for print_int +li $a0, 5 # integer to print +syscall # print it + +#exit() +li $v0, 10 +syscall \ No newline at end of file diff --git a/src/mips/print_str.asm b/src/mips/print_str.asm new file mode 100644 index 00000000..756e17cc --- /dev/null +++ b/src/mips/print_str.asm @@ -0,0 +1,11 @@ +.data + hello: .asciiz "Hello, world!" + +.text + li $v0, 4 # system call code for print_str + la $a0, hello # str to print + syscall # print it + + #exit() + li $v0, 10 + syscall \ No newline at end of file diff --git a/src/parserTest.py b/src/parserTest.py new file mode 100644 index 00000000..9c01f9ff --- /dev/null +++ b/src/parserTest.py @@ -0,0 +1,40 @@ +import lexer_rules +import parser_rules +import sys + +from ply.lex import lex +from ply.yacc import yacc + +def run(addr): + lexer = lex(module=lexer_rules) + parser = yacc(module=parser_rules) + with open(addr, encoding = "utf-8") as f: + text = f.read() + + parser.parse(text, lexer) + + # temp = parser_rules.result.split(':') + # s = temp[0] + # parser_rules.result = '' + # return s + + if parser_rules.my_bool: + print(parser_rules.result + '\n') + parser_rules.result = '' + parser_rules.my_bool = False + exit(1) + + +# lexer = lex(module=lexer_rules) +# parser = yacc(module=parser_rules) + +# text = "" +# lexer = lex(module=lexer_rules) + +# fpath = "C:/Users/Eziel/Desktop/ejemplos/cool-compiler-jj-christian-alberto-hector-c411/src/test/TestCases/Semantics/success/" +# fpath = fpath + 'binary_tree.cl' + +# with open(fpath, encoding = "utf-8") as file: +# text = file.read() + +# parser.parse(text, lexer) \ No newline at end of file diff --git a/src/parser_rules.py b/src/parser_rules.py new file mode 100644 index 00000000..558dbb89 --- /dev/null +++ b/src/parser_rules.py @@ -0,0 +1,361 @@ +from lexer_rules import tokens +import AST +#from expressions import * + +from operator import add, mul +#from expressions import BinaryOperation, Number + +my_bool = False +result = '' + +# Parsing rules +precedence = ( + ('right', 'ASSIGN'), + ('right', 'NOT'), + ('nonassoc', 'LTEQ', 'LT', 'EQ'), + ('left', 'PLUS', 'MINUS'), + ('left', 'MULTIPLY', 'DIVIDE'), + ('right', 'ISVOID'), + ('right', 'INT_COMP'), + ('left', 'AT'), + ('left', 'DOT') +) +# precedence = ( +# ('left','PLUS','MINUS'), +# ('left','MULTIPLY','DIVIDE'), +# ('right','ASSIGN'), +# ('left','NOT'), +# ('nonassoc','LT','LTEQ','EQ'), +# ('right','ISVOID'), +# ('right','INT_COMP'), +# ('left','AT'), +# ('left','DOT') +# ) + +def p_program(production): + '''program : classSet''' + production[0] = AST.Program(production[1]) + production[0].line = 1 + +def p_classSet(production): + ''' + classSet : class SEMICOLON classSet + | class SEMICOLON + ''' + if len(production) == 3: + production[0] = [production[1]] + else: production[0] = [production[1]] + production[3] + +def p_class(production): + 'class : CLASS TYPE _inherits LBRACE ffeature RBRACE' + production[0] = AST.Class(production[2], production[3], production[5]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_inherits(production): + '''_inherits : INHERITS TYPE + | empty''' + if len(production) == 3: + production[0] = AST.Type(production[2]) + else: production[0] = None + +def p_ffeature(production): + '''ffeature : feature SEMICOLON ffeature + | empty''' + if len(production) == 4: + production[0] = [production[1]] + production[3] #creo la lista de metodos y atributos + else: production[0] = [] + +def p_feature(production): #metodo || atributo + #definition: name (args):returnType{expr} + '''feature : ID LPAREN formal RPAREN TDOTS TYPE LBRACE expr RBRACE + | ID LPAREN RPAREN TDOTS TYPE LBRACE expr RBRACE + | temp + ''' + if len(production) == 10: + production[0] = AST.Method(production[1], production[3], production[6], production[8]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + elif len(production) == 9: + production[0] = AST.Method(production[1], [], production[5], production[7]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + else:#atr + production[0] = production[1] + production[0].line = production[1].line + production[0].index = production[1].index + +#cambiar temp por atributos o variables +def p_temp(production): + ''' + temp : idDots + | idDots ASSIGN expr + ''' + if len(production) == 2: + production[0] = production[1] + else: + production[0] = AST.Attribute(production[1].id, production[1].type, production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + +def p_idDots(production): + 'idDots : ID TDOTS TYPE' + production[0] = AST.Var(production[1], production[3]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_formal(production): + '''formal : idDots COMMA formal + | idDots''' + if len(production) == 2: + production[0] = [production[1]] + else: production[0] = [production[1]] + production[3] + +def p_expression_list(production): + '''expression_list : expression_list expr SEMICOLON + | expr SEMICOLON + ''' + if len(production) == 3: + production[0] = [production[1]] + else: production[0] = production[1] + [production[2]] + +def p_expression_not(production): #boolean complement of + '''expr : NOT expr''' + production[0] = AST.Not(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_binop(production): + '''expr : expr PLUS expr + | expr MINUS expr + | expr MULTIPLY expr + | expr DIVIDE expr''' + if production[2] == '+': + production[0] = AST.Plus(production[1], production[3]) + elif production[2] == '-': + production[0] = AST.Minus(production[1], production[3]) + elif production[2] == '*': + production[0] = AST.Star(production[1], production[3]) + elif production[2] == '/': + production[0] = AST.Div(production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + +def p_expression_g(production): + ''' + expr : LPAREN expr RPAREN + | ISVOID expr + | block + | conditional + | loop + | case + | dispatch + | INT_COMP expr + ''' + if len(production) == 4: + production[0] = production[2] + elif len(production) == 3: + if production[1] == 'isvoid': + production[0] = AST.IsVoid(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + else: + production[0] = AST.IntegerComplement(production[2]) + production[0].line = production.lineno(1) + production[0].index = production[2].index + # line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + # production[0].index = production.lexpos(1) - line_start + 1 + else: production[0] = production[1] + +def p_block(production): + 'block : LBRACE expression_list RBRACE' + production[0] = AST.Block(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_id(production): + '''expr : ID''' + production[0] = AST.Type(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_int(production): + '''expr : INTEGER ''' + production[0] = AST.Interger(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_str(production): + '''expr : STRING''' + production[0] = AST.String(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_bool(production): + '''expr : TRUE + | FALSE''' + production[0] = AST.Boolean(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_newtype(production): + '''expr : NEW TYPE''' + production[0] = AST.NewType(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_l(production): + '''expr : let''' + production[0] = production[1] + +#e_0.f(e_1,...,e_n) +def p_dispatch(production): + ''' + dispatch : expr DOT ID LPAREN arguments_list_opt RPAREN + | expr AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + | ID LPAREN arguments_list_opt RPAREN + ''' + if len(production) == 7: + production[0] = AST.Dispatch(production[3], production[5], production[1]) + production[0].line = production.lineno(2) + # line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + # production[0].index = production.lexpos(2) - line_start + 1 + production[0].index = production[1].index + elif len(production) == 5: + production[0] = AST.Dispatch(production[1], production[3], None) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + else: + production[0] = AST.StaticDispatch(production[5], production[7], production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + +def p_arguments_list(production): + """ + arguments_list : arguments_list COMMA expr + | expr + """ + if len(production) == 4: + production[0] = production[1] + [production[3]] + else: production[0] = [production[1]] + +def p_arguments_list_opt(production): + """ + arguments_list_opt : arguments_list + | empty + """ + production[0] = [] if production.slice[1].type == "empty" else production[1] + + +def p_empty(production): + 'empty :' + production[0] = None + +def p_let_expression(production): + 'let : LET declaration_list IN expr' + production[0] = AST.LetVar(production[2], production[4]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_declaration_list(production): + ''' + declaration_list : temp COMMA declaration_list + | temp + ''' + if len(production) == 2: + production[0] = [production[1]] + else: production[0] = [production[1]] + production[3] + +def p_conditional(production): + 'conditional : IF expr THEN expr ELSE expr FI' + production[0] = AST.Conditional(production[2], production[4], production[6]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_loop(production): + 'loop : WHILE expr LOOP expr POOL' + production[0] = AST.Loop(production[2], production[4]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_case(production): + 'case : CASE expr OF add ESAC' + production[0] = AST.Case(production[2], production[4]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_add(production): + '''add : derivate SEMICOLON add + | derivate SEMICOLON + ''' + if len(production) == 4: + production[0] = [production[1]] + production[3] + else: production[0] = [production[1]] + +def p_derivate(production): + '''derivate : idDots ARROW expr''' + production[0] = AST.Branch(production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + + +def p_expression_cmp(production): + '''expr : expr LT expr + | expr LTEQ expr + | expr EQ expr''' + if production[2] == '<': + production[0] = AST.LowerThan(production[1], production[3]) + elif production[2] == '<=': + production[0] = AST.LowerEqualThan(production[1], production[3]) + elif production[2] == '=': + production[0] = AST.EqualThan(production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + + +def p_expression_assign(production): + 'expr : ID ASSIGN expr' + production[0] = AST.Assign(production[1], production[3]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def find_column(production): + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos) + 1 + return production.lexpos - line_start + 1 + +def p_error(production): + global my_bool + global result + """ + Error rule for Syntax Errors handling and reporting. + """ + if production is None: + result = '(0, 0) - SyntacticError: ERROR at or near EOF' + #print('(0, 0) - SyntacticError: ERROR at or near EOF') + else: + result = '({}, {}) - SyntacticError: ERROR at or near "{}"'.format(production.lineno, find_column(production), production.value) + #print('({}, {}) - SyntacticError: ERROR at or near "{}"'.format( production.lineno, find_column(production), production.value)) + my_bool = True \ No newline at end of file diff --git a/src/parsetab.py b/src/parsetab.py new file mode 100644 index 00000000..14565620 --- /dev/null +++ b/src/parsetab.py @@ -0,0 +1,90 @@ + +# parsetab.py +# This file is automatically generated. Do not edit. +# pylint: disable=W,C,R +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'rightASSIGNrightNOTnonassocLTEQLTEQleftPLUSMINUSleftMULTIPLYDIVIDErightISVOIDrightINT_COMPleftATleftDOTARROW ASSIGN AT CASE CLASS COMMA DIVIDE DOT ELSE EQ ESAC FALSE FI ID IF IN INHERITS INTEGER INT_COMP ISVOID LBRACE LET LOOP LPAREN LT LTEQ MINUS MULTIPLY NEW NOT OF PLUS POOL RBRACE RPAREN SEMICOLON STRING TDOTS THEN TRUE TYPE WHILEprogram : classSet\n classSet : class SEMICOLON classSet\n | class SEMICOLON\n class : CLASS TYPE _inherits LBRACE ffeature RBRACE_inherits : INHERITS TYPE\n | emptyffeature : feature SEMICOLON ffeature\n | emptyfeature : ID LPAREN formal RPAREN TDOTS TYPE LBRACE expr RBRACE\n | ID LPAREN RPAREN TDOTS TYPE LBRACE expr RBRACE\n | temp\n \n temp : idDots\n | idDots ASSIGN expr\n idDots : ID TDOTS TYPEformal : idDots COMMA formal\n | idDotsexpression_list : expression_list expr SEMICOLON \n | expr SEMICOLON\n expr : NOT exprexpr : expr PLUS expr \n | expr MINUS expr\n | expr MULTIPLY expr\n | expr DIVIDE expr\n expr : LPAREN expr RPAREN\n | ISVOID expr\n | block\n | conditional\n | loop\n | case\n | dispatch\n | INT_COMP expr\n block : LBRACE expression_list RBRACEexpr : IDexpr : INTEGER expr : STRINGexpr : TRUE\n | FALSEexpr : NEW TYPEexpr : let\n dispatch : expr DOT ID LPAREN arguments_list_opt RPAREN\n | expr AT TYPE DOT ID LPAREN arguments_list_opt RPAREN\n | ID LPAREN arguments_list_opt RPAREN\n \n arguments_list : arguments_list COMMA expr\n | expr\n \n arguments_list_opt : arguments_list\n | empty\n empty :let : LET declaration_list IN expr\n declaration_list : temp COMMA declaration_list\n | temp\n conditional : IF expr THEN expr ELSE expr FIloop : WHILE expr LOOP expr POOLcase : CASE expr OF add ESACadd : derivate SEMICOLON add\n | derivate SEMICOLON\n derivate : idDots ARROW exprexpr : expr LT expr\n | expr LTEQ expr\n | expr EQ exprexpr : ID ASSIGN expr' + +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),'SEMICOLON':([3,14,17,18,19,29,30,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,72,81,82,83,84,85,86,87,90,91,96,97,108,114,116,124,125,129,130,134,135,137,138,],[5,20,-11,-12,-4,-14,-13,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,98,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,110,-42,126,-48,-52,-53,-10,-40,-56,-9,-51,-41,]),'TYPE':([4,9,22,45,53,63,78,],[6,12,29,70,79,89,104,]),'INHERITS':([6,],[9,]),'LBRACE':([6,8,10,12,23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,79,98,99,100,102,104,105,106,109,110,118,123,127,131,],[-47,11,-6,-5,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,105,-18,47,47,47,118,47,47,47,-17,47,47,47,47,]),'ID':([11,20,21,23,31,32,33,39,47,48,49,50,51,54,55,56,57,58,59,60,61,62,68,69,71,98,99,100,101,102,103,105,106,107,109,110,118,123,126,127,131,],[16,16,25,40,40,40,40,40,40,40,40,40,25,25,40,40,40,40,40,40,40,88,40,40,40,-18,40,40,25,40,25,40,40,121,40,-17,40,40,25,40,40,]),'RBRACE':([11,13,15,20,24,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,71,81,82,83,84,85,86,87,90,91,96,98,108,110,116,119,124,125,128,130,137,138,],[-47,19,-8,-47,-7,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,96,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-18,-42,-17,-48,129,-52,-53,135,-40,-51,-41,]),'LPAREN':([16,23,31,32,33,39,40,47,48,49,50,55,56,57,58,59,60,61,68,69,71,88,98,99,100,102,105,106,109,110,118,121,123,127,131,],[21,32,32,32,32,32,69,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,-18,32,32,32,32,32,32,-17,32,131,32,32,32,]),'TDOTS':([16,25,27,52,],[22,22,53,78,]),'COMMA':([18,28,29,30,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,77,81,82,83,84,85,86,87,90,91,93,95,96,108,116,122,124,125,130,137,138,],[-12,54,-14,-13,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,103,-20,-21,-22,-23,-57,-58,-59,-24,-60,109,-44,-32,-42,-48,-43,-52,-53,-40,-51,-41,]),'IN':([18,29,30,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,76,77,81,82,83,84,85,86,87,90,91,96,108,116,117,124,125,130,137,138,],[-12,-14,-13,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,102,-50,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-49,-52,-53,-40,-51,-41,]),'ASSIGN':([18,29,40,],[23,-14,68,]),'RPAREN':([21,26,28,29,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,69,70,80,81,82,83,84,85,86,87,90,91,92,93,94,95,96,106,108,116,120,122,124,125,130,131,136,137,138,],[27,52,-16,-14,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,90,-25,-31,-47,-38,-15,-20,-21,-22,-23,-57,-58,-59,-24,-60,108,-45,-46,-44,-32,-47,-42,-48,130,-43,-52,-53,-40,-47,138,-51,-41,]),'NOT':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,-18,31,31,31,31,31,31,-17,31,31,31,31,]),'ISVOID':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,-18,33,33,33,33,33,33,-17,33,33,33,33,]),'INT_COMP':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,-18,39,39,39,39,39,39,-17,39,39,39,39,]),'INTEGER':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,-18,41,41,41,41,41,41,-17,41,41,41,41,]),'STRING':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,-18,42,42,42,42,42,42,-17,42,42,42,42,]),'TRUE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,-18,43,43,43,43,43,43,-17,43,43,43,43,]),'FALSE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,-18,44,44,44,44,44,44,-17,44,44,44,44,]),'NEW':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,-18,45,45,45,45,45,45,-17,45,45,45,45,]),'IF':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,-18,48,48,48,48,48,48,-17,48,48,48,48,]),'WHILE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,-18,49,49,49,49,49,49,-17,49,49,49,49,]),'CASE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,-18,50,50,50,50,50,50,-17,50,50,50,50,]),'LET':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,-18,51,51,51,51,51,51,-17,51,51,51,51,]),'ARROW':([29,115,],[-14,127,]),'PLUS':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[55,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,55,55,-25,-31,-38,55,55,55,55,-20,-21,-22,-23,55,55,55,-24,55,55,-32,55,-42,55,55,55,55,55,-52,-53,55,-40,55,55,-51,-41,]),'MINUS':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[56,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,56,56,-25,-31,-38,56,56,56,56,-20,-21,-22,-23,56,56,56,-24,56,56,-32,56,-42,56,56,56,56,56,-52,-53,56,-40,56,56,-51,-41,]),'MULTIPLY':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[57,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,57,57,-25,-31,-38,57,57,57,57,57,57,-22,-23,57,57,57,-24,57,57,-32,57,-42,57,57,57,57,57,-52,-53,57,-40,57,57,-51,-41,]),'DIVIDE':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[58,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,58,58,-25,-31,-38,58,58,58,58,58,58,-22,-23,58,58,58,-24,58,58,-32,58,-42,58,58,58,58,58,-52,-53,58,-40,58,58,-51,-41,]),'LT':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[59,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,59,59,-25,-31,-38,59,59,59,59,-20,-21,-22,-23,None,None,None,-24,59,59,-32,59,-42,59,59,59,59,59,-52,-53,59,-40,59,59,-51,-41,]),'LTEQ':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[60,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,60,60,-25,-31,-38,60,60,60,60,-20,-21,-22,-23,None,None,None,-24,60,60,-32,60,-42,60,60,60,60,60,-52,-53,60,-40,60,60,-51,-41,]),'EQ':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[61,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,61,61,-25,-31,-38,61,61,61,61,-20,-21,-22,-23,None,None,None,-24,61,61,-32,61,-42,61,61,61,61,61,-52,-53,61,-40,61,61,-51,-41,]),'DOT':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,89,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[62,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,62,62,62,62,-38,62,62,62,62,62,62,62,62,62,62,62,107,-24,62,62,-32,62,-42,62,62,62,62,62,-52,-53,62,-40,62,62,-51,-41,]),'AT':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[63,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,63,63,63,63,-38,63,63,63,63,63,63,63,63,63,63,63,-24,63,63,-32,63,-42,63,63,63,63,63,-52,-53,63,-40,63,63,-51,-41,]),'THEN':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,73,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,99,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,-51,-41,]),'LOOP':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,74,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,100,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,-51,-41,]),'OF':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,75,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,101,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,-51,-41,]),'ELSE':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,81,82,83,84,85,86,87,90,91,96,108,111,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,123,-48,-52,-53,-40,-51,-41,]),'POOL':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,81,82,83,84,85,86,87,90,91,96,108,112,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,124,-48,-52,-53,-40,-51,-41,]),'FI':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,132,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,137,-51,-41,]),'ESAC':([113,126,133,],[125,-55,-54,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'program':([0,],[1,]),'classSet':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'_inherits':([6,],[8,]),'empty':([6,11,20,69,106,131,],[10,15,15,94,94,94,]),'ffeature':([11,20,],[13,24,]),'feature':([11,20,],[14,14,]),'temp':([11,20,51,103,],[17,17,77,77,]),'idDots':([11,20,21,51,54,101,103,126,],[18,18,28,18,28,115,18,115,]),'formal':([21,54,],[26,80,]),'expr':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[30,64,65,66,67,72,73,74,75,81,82,83,84,85,86,87,91,95,97,111,112,116,119,95,122,128,132,134,95,]),'block':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,]),'conditional':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,]),'loop':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,]),'case':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'dispatch':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'let':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'expression_list':([47,],[71,]),'declaration_list':([51,103,],[76,117,]),'arguments_list_opt':([69,106,131,],[92,120,136,]),'arguments_list':([69,106,131,],[93,93,93,]),'add':([101,126,],[113,133,]),'derivate':([101,126,],[114,114,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> program","S'",1,None,None,None), + ('program -> classSet','program',1,'p_program','parser_rules.py',36), + ('classSet -> class SEMICOLON classSet','classSet',3,'p_classSet','parser_rules.py',42), + ('classSet -> class SEMICOLON','classSet',2,'p_classSet','parser_rules.py',43), + ('class -> CLASS TYPE _inherits LBRACE ffeature RBRACE','class',6,'p_class','parser_rules.py',50), + ('_inherits -> INHERITS TYPE','_inherits',2,'p_inherits','parser_rules.py',57), + ('_inherits -> empty','_inherits',1,'p_inherits','parser_rules.py',58), + ('ffeature -> feature SEMICOLON ffeature','ffeature',3,'p_ffeature','parser_rules.py',64), + ('ffeature -> empty','ffeature',1,'p_ffeature','parser_rules.py',65), + ('feature -> ID LPAREN formal RPAREN TDOTS TYPE LBRACE expr RBRACE','feature',9,'p_feature','parser_rules.py',71), + ('feature -> ID LPAREN RPAREN TDOTS TYPE LBRACE expr RBRACE','feature',8,'p_feature','parser_rules.py',72), + ('feature -> temp','feature',1,'p_feature','parser_rules.py',73), + ('temp -> idDots','temp',1,'p_temp','parser_rules.py',94), + ('temp -> idDots ASSIGN expr','temp',3,'p_temp','parser_rules.py',95), + ('idDots -> ID TDOTS TYPE','idDots',3,'p_idDots','parser_rules.py',106), + ('formal -> idDots COMMA formal','formal',3,'p_formal','parser_rules.py',113), + ('formal -> idDots','formal',1,'p_formal','parser_rules.py',114), + ('expression_list -> expression_list expr SEMICOLON','expression_list',3,'p_expression_list','parser_rules.py',120), + ('expression_list -> expr SEMICOLON','expression_list',2,'p_expression_list','parser_rules.py',121), + ('expr -> NOT expr','expr',2,'p_expression_not','parser_rules.py',128), + ('expr -> expr PLUS expr','expr',3,'p_expression_binop','parser_rules.py',135), + ('expr -> expr MINUS expr','expr',3,'p_expression_binop','parser_rules.py',136), + ('expr -> expr MULTIPLY expr','expr',3,'p_expression_binop','parser_rules.py',137), + ('expr -> expr DIVIDE expr','expr',3,'p_expression_binop','parser_rules.py',138), + ('expr -> LPAREN expr RPAREN','expr',3,'p_expression_g','parser_rules.py',153), + ('expr -> ISVOID expr','expr',2,'p_expression_g','parser_rules.py',154), + ('expr -> block','expr',1,'p_expression_g','parser_rules.py',155), + ('expr -> conditional','expr',1,'p_expression_g','parser_rules.py',156), + ('expr -> loop','expr',1,'p_expression_g','parser_rules.py',157), + ('expr -> case','expr',1,'p_expression_g','parser_rules.py',158), + ('expr -> dispatch','expr',1,'p_expression_g','parser_rules.py',159), + ('expr -> INT_COMP expr','expr',2,'p_expression_g','parser_rules.py',160), + ('block -> LBRACE expression_list RBRACE','block',3,'p_block','parser_rules.py',179), + ('expr -> ID','expr',1,'p_expression_id','parser_rules.py',186), + ('expr -> INTEGER','expr',1,'p_expression_int','parser_rules.py',193), + ('expr -> STRING','expr',1,'p_expression_str','parser_rules.py',200), + ('expr -> TRUE','expr',1,'p_expression_bool','parser_rules.py',207), + ('expr -> FALSE','expr',1,'p_expression_bool','parser_rules.py',208), + ('expr -> NEW TYPE','expr',2,'p_expression_newtype','parser_rules.py',215), + ('expr -> let','expr',1,'p_expression_l','parser_rules.py',222), + ('dispatch -> expr DOT ID LPAREN arguments_list_opt RPAREN','dispatch',6,'p_dispatch','parser_rules.py',228), + ('dispatch -> expr AT TYPE DOT ID LPAREN arguments_list_opt RPAREN','dispatch',8,'p_dispatch','parser_rules.py',229), + ('dispatch -> ID LPAREN arguments_list_opt RPAREN','dispatch',4,'p_dispatch','parser_rules.py',230), + ('arguments_list -> arguments_list COMMA expr','arguments_list',3,'p_arguments_list','parser_rules.py',251), + ('arguments_list -> expr','arguments_list',1,'p_arguments_list','parser_rules.py',252), + ('arguments_list_opt -> arguments_list','arguments_list_opt',1,'p_arguments_list_opt','parser_rules.py',260), + ('arguments_list_opt -> empty','arguments_list_opt',1,'p_arguments_list_opt','parser_rules.py',261), + ('empty -> ','empty',0,'p_empty','parser_rules.py',267), + ('let -> LET declaration_list IN expr','let',4,'p_let_expression','parser_rules.py',271), + ('declaration_list -> temp COMMA declaration_list','declaration_list',3,'p_declaration_list','parser_rules.py',279), + ('declaration_list -> temp','declaration_list',1,'p_declaration_list','parser_rules.py',280), + ('conditional -> IF expr THEN expr ELSE expr FI','conditional',7,'p_conditional','parser_rules.py',287), + ('loop -> WHILE expr LOOP expr POOL','loop',5,'p_loop','parser_rules.py',294), + ('case -> CASE expr OF add ESAC','case',5,'p_case','parser_rules.py',301), + ('add -> derivate SEMICOLON add','add',3,'p_add','parser_rules.py',308), + ('add -> derivate SEMICOLON','add',2,'p_add','parser_rules.py',309), + ('derivate -> idDots ARROW expr','derivate',3,'p_derivate','parser_rules.py',316), + ('expr -> expr LT expr','expr',3,'p_expression_cmp','parser_rules.py',324), + ('expr -> expr LTEQ expr','expr',3,'p_expression_cmp','parser_rules.py',325), + ('expr -> expr EQ expr','expr',3,'p_expression_cmp','parser_rules.py',326), + ('expr -> ID ASSIGN expr','expr',3,'p_expression_assign','parser_rules.py',339), +] diff --git a/src/semanticTest.py b/src/semanticTest.py new file mode 100644 index 00000000..5010f793 --- /dev/null +++ b/src/semanticTest.py @@ -0,0 +1,22 @@ +import lexer_rules +import parser_rules +import sys + +from ply.lex import lex +from ply.yacc import yacc +from semantic_rules import Semantic + +def run(addr): + lexer = lex(module=lexer_rules) + parser = yacc(module=parser_rules) + sem = Semantic() + + with open(addr, encoding = "utf-8") as f: + text = f.read() + + ast = parser.parse(text, lexer) + sem.visit(ast) + + if len(sem.error) > 0: + print(sem.error[0] + '\n') + exit(1) diff --git a/src/semantic_rules.py b/src/semantic_rules.py new file mode 100644 index 00000000..a0f5ee22 --- /dev/null +++ b/src/semantic_rules.py @@ -0,0 +1,705 @@ +import visitor as visitor +from AST import * +import tools + + +class Semantic: + def __init__(self): + self.error = [] + #classes + self.classmethods = {} + self.classmethods['Object'] = { + 'abort': ([],'Object'), + 'type_name':([],'String'), + 'copy': ([],'SELF_TYPE')} + self.classmethods['IO'] = { + 'out_string': ([('x','String')] , 'SELF_TYPE'), + 'out_int': ([('x','Int')] , 'SELF_TYPE'), + 'in_string': ([], 'String'), + 'in_int': ([], 'Int')} + self.classmethods['Int'] = {} + self.classmethods['String'] = { + 'length': ([], 'Int'), + 'concat': ([('s','String')], 'String'), + 'substr': ([('i','Int'), ('l','Int')], 'String')} + self.classmethods['Bool'] = {} + self.classmethods_original = {} + self.class_attrs = {'Object':[], 'IO':[], 'Int':[], 'String':[], 'Bool':[]} + self.graph = {} + self.local_variables = [('self', 'SELF_TYPE')] + self.current_class = None + self.current_method = None + self.class_parent = {'Int':'Object', 'String':'Object', 'Bool':'Object', 'IO':'Object'} + self.conforms = { + 'Object':set(['Object']), + 'Int':set(['Object','Int']), + 'String':set(['Object','String']), + 'IO':set(['Object','IO']), + 'Bool':set(['Object','Bool'])} + #conforms to + + def lca(self, type1, type2): + temp = type1 + parents = set([temp]) + while temp != 'Object': + temp = self.class_parent[temp] + parents.add(temp) + + temp = type2 + while not parents.__contains__(temp): + temp = self.class_parent[temp] + + return temp + + def check_eq(self, method1, method2): + args1 = method1[0] + return_type1 = method1[1] + + args2 = method2[0] + return_type2 = method2[1] + + if return_type1 != return_type2 or len(args1) != len(args2): + return False + + n = len(args1) + for i in range(n): + if args1[i][1] != args2[i][1]: + return False + return True + + def ComputeInheritsfeature(self, program): + l = ['Object'] + while len(l) > 0: + temp = l[0] + l.pop(0) + if not self.graph.__contains__(temp): + continue + for c in self.graph[temp]: + last = len(self.class_attrs[temp]) - 1 + for i in range(last, -1, -1): + self.class_attrs[c].insert(0, self.class_attrs[temp][i]) + + self.conforms[c].update(self.conforms[temp]) + l.append(c) + for m in self.classmethods[temp].items(): + if not self.classmethods[c].__contains__(m[0]): + # SI NO CONTIENE EL METODO, LO AGREGO A LA CLASE + self.classmethods[c][m[0]] = m[1] + elif not self.check_eq(m[1], self.classmethods[c][m[0]]): + for _class in program.classes: + if _class.name == c: + for _method in _class.methods: + if _method.id == m[0]: + self.error.append('({}, {}) - SemanticError: the types of the formal parameters, and the return type are not exactly the same in both definitions.'.format(_method.line, _method.index)) + return False + return True + + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(Program) + def visit(self, program): + '''Classes defined only once''' + for c in program.classes: + if not self.classmethods.__contains__(c.name): + self.classmethods[c.name] = {} + self.conforms[c.name] = set([c.name]) + else: + self.error.append('({}, {}) - SemanticError: Classes may not be redefined.'.format(c.line, c.index)) + return False + self.class_attrs[c.name] = c.attributes + for m in c.methods: + if self.classmethods[c.name].__contains__(m.id): + self.error.append('({}, {}) - SemanticError: Method {} is multiply defined.'.format(m.line, m.index, m.id)) + return False + params = [(v.id, v.type) for v in m.parameters] + self.classmethods[c.name][m.id] = (params, m.return_type) + + if not self.classmethods.__contains__('Main'): + #print('Every program must have a class Main') + return False + + '''Inheritance relationships''' + classes = self.classmethods.keys() + self.graph['Object'] = ['Int', 'String', 'Bool', 'IO'] + for c in program.classes: + if c.inherit is None: + self.graph['Object'].append(c.name) + self.conforms[c.name].add('Object') + self.class_parent[c.name] = 'Object' + elif not self.classmethods.__contains__(c.inherit.name): + self.error.append('({}, {}) - TypeError: Class {} inherits from an undefined class {}.'.format(c.line, c.index, c.name, c.inherit.name)) + return False + elif c.inherit.name == 'Int' or c.inherit.name =='String' or c.inherit.name =='Bool' or c.inherit.name =='Object': + self.error.append('({}, {}) - SemanticError: Class {} cannot inherit class {}.'.format(c.line, c.index, c.name, c.inherit.name)) + return False + else: + if self.graph.__contains__(c.inherit.name): + self.graph[c.inherit.name].append(c.name) #c.name is a child class of c.inherit + else: self.graph[c.inherit.name] = [c.name] + self.class_parent[c.name] = c.inherit.name + self.conforms[c.name].add(c.inherit.name) + if tools.dfs(self.graph, classes):#si hay ciclo + self.error.append('({}, {}) - SemanticError: Class {}, or an ancestor of {}, is involved in an inheritance cycle.'.format(c.line, c.index, c.name, c.name)) + return False + + self.classmethods_original.update(self.classmethods) + if not self.ComputeInheritsfeature(program): + return False + + for _cl in classes: + for _item in self.classmethods[_cl].items(): + if _item[1][1] == 'SELF_TYPE': + _new = (_item[1][0],_cl) + self.classmethods[_cl][_item[0]] = _new + + for c in program.classes: + if not self.graph.__contains__(c.name): + atr_id = set([x.id for x in self.class_attrs[c.name]]) + if len(atr_id) < len(self.class_attrs[c.name]): + _redefinedID = set([]) + for item in self.class_attrs[c.name]: + if _redefinedID.__contains__(item.id): + self.error.append('({}, {}) - SemanticError: Attribute redef.'.format(item.line, item.index)) + return False + else: _redefinedID.add(item.id) + + for _item in self.class_attrs.items(): + n = len(_item[1]) + for i in range(n): + if _item[1][i].type == 'SELF_TYPE': + _item[1][i].type = _item[0] + + '''visito las clases''' + for c in program.classes: + if not self.visit(c): + return False + return True + + @visitor.when(Class) + def visit(self, _class): + + if _class.name == 'Main': + if not self.classmethods[_class.name].__contains__('main'): + #print('error: Main class must have a method main') + return False + elif len(self.classmethods['Main']['main'][0]) > 0: + #print('error: main takes no formal parameters') + return False + + self.current_class = _class.name + + for m in _class.methods: + if not self.visit(m): + return False + + #importante + for atr in _class.attributes: + if not self.visit(atr): + return False + + self.current_class = None + return True + + @visitor.when(Method) + def visit(self, method): + + for formal in method.parameters: + if not self.visit(formal): + return False + + args = method.parameters + if not method.parameters is None: + args_id = set([arg.id for arg in args]) + if len(args_id) < len(args): + self.error.append('({}, {}) - SemanticError: The identifiers used in the formal parameter list must be distinct.'.format(method.line, method.index)) + return False + + self.current_method = method.id + if not self.visit(method.expression): + return False + + self.local_variables.clear() + self.local_variables.append(('self','SELF_TYPE')) + self.current_method = None + _returnType = method.return_type if method.return_type != 'SELF_TYPE' else self.current_class + if not self.conforms[method.expression.static_type].__contains__(_returnType): + self.error.append('({}, {}) - TypeError: Inferred return type {} of method {} does not conform to declared return type {}.'.format(method.line, method.expression.index, method.expression.static_type, method.id, _returnType)) + return False + return True + + + + @visitor.when(Block) + def visit(self, block): + + for e in block.expressions: + if not self.visit(e): + return False + + n = len(block.expressions) - 1 + block.static_type = block.expressions[n].static_type + return True + + + + @visitor.when(Star) + def visit(self, star): + if not self.visit(star.first): + return False + if not self.visit(star.second): + return False + if star.first.static_type != "Int" or star.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} * {}'.format(star.line, star.index,star.first.static_type,star.second.static_type)) + return False + star.static_type = 'Int' + return True + + @visitor.when(Plus) + def visit(self, plus): + if not self.visit(plus.first): + return False + if not self.visit(plus.second): + return False + if plus.first.static_type != "Int" or plus.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} + {}'.format(plus.line, plus.index, plus.first.static_type, plus.second.static_type)) + return False + plus.static_type = 'Int' + return True + + @visitor.when(Minus) + def visit(self, minus): + if not self.visit(minus.first): + return False + if not self.visit(minus.second): + return False + if minus.first.static_type != "Int" or minus.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} - {}'.format(minus.line, minus.index,minus.first.static_type, minus.second.static_type)) + return False + minus.static_type = 'Int' + return True + + @visitor.when(Div) + def visit(self, div): + if not self.visit(div.first): + return False + if not self.visit(div.second): + return False + if div.first.static_type != "Int" or div.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} / {}'.format(div.line, div.index, div.first.static_type, div.second.static_type)) + return False + div.static_type = 'Int' + return True + + + + + + @visitor.when(LowerEqualThan) + def visit(self, lowerEqualThan): + if not self.visit(lowerEqualThan.first): + return False + + if not self.visit(lowerEqualThan.second): + return False + + if lowerEqualThan.first.static_type != "Int" or lowerEqualThan.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} <= {}'.format(lowerEqualThan.line, lowerEqualThan.index,lowerEqualThan.first.static_type,lowerEqualThan.second.static_type)) + return False + + lowerEqualThan.static_type = 'Bool' + return True + + @visitor.when(EqualThan) + def visit(self, equalThan): + if not self.visit(equalThan.first): + return False + + if not self.visit(equalThan.second): + return False + + if equalThan.first.static_type == 'Int' or equalThan.first.static_type == 'String' or equalThan.first.static_type == 'Bool': + if equalThan.first.static_type != equalThan.second.static_type: + self.error.append('({}, {}) - TypeError: Illegal comparison with a basic type.'.format(equalThan.line, equalThan.index)) + return False + + equalThan.static_type = 'Bool' + return True + + @visitor.when(LowerThan) + def visit(self, lowerThan): + if not self.visit(lowerThan.first): + return False + if not self.visit(lowerThan.second): + return False + if lowerThan.first.static_type != 'Int' or lowerThan.second.static_type != 'Int': + self.error.append('({}, {}) - TypeError: non-Int arguments: {} < {}'.format(lowerThan.line, lowerThan.index,lowerThan.first.static_type,lowerThan.second.static_type)) + return False + + lowerThan.static_type = 'Bool' + return True + + + + @visitor.when(Not) + def visit(self, negation): + if not self.visit(negation.expr): + return False + + if negation.expr.static_type != 'Bool': + self.error.append("({}, {}) - TypeError: Argument of 'not' has type {} instead of Bool.".format(negation.line, negation.index, negation.expr.static_type)) + return False + + negation.static_type = 'Bool' + return True + + @visitor.when(IntegerComplement) + def visit(self, I_complement): + + if not self.visit(I_complement.expression): + return False + + if I_complement.expression.static_type != "Int": + self.error.append("({}, {}) - TypeError: Argument of '~' has type {} instead of Int.".format(I_complement.line, I_complement.index, I_complement.expression.static_type)) + return False + + I_complement.static_type = 'Int' + return True + + + @visitor.when(IsVoid) + def visit(self, is_void): + + if not self.visit(is_void.expression): + return False + + is_void.static_type = 'Bool' + return True + + + + + + + @visitor.when(Type) + def visit(self, _type): + #expr --> ID + + #verificar si esta declarado + if _type.name == 'self': + _type.static_type = self.current_class + return True + else: + n = len(self.local_variables) - 1 + for i in range(n, -1, -1): + local_id, local_type = self.local_variables[i] + if local_id == _type.name: + _type.static_type = local_type + return True + + if not self.current_method is None: + for args_id,args_type in self.classmethods[self.current_class][self.current_method][0]: + if args_id == _type.name: + _type.static_type = args_type + return True + + for _var in self.class_attrs[self.current_class]: + attr_id = _var.id + attr_type = _var.type + if attr_id == _type.name: + _type.static_type = attr_type + return True + + #print("error: tipo no declarado") + self.error.append('({}, {}) - NameError: Undeclared identifier {}.'.format(_type.line, _type.index, _type.name)) + return False + + + @visitor.when(NewType) + def visit(self, new_type): + if new_type.type_name == 'SELF_TYPE': + new_type.static_type = self.current_class + else: + if not self.classmethods.__contains__(new_type.type_name): + self.error.append("({}, {}) - TypeError: 'new' used with undefined class {}.".format(new_type.line, new_type.index, new_type.type_name)) + return False + new_type.static_type = new_type.type_name + return True + + + @visitor.when(Boolean) + def visit(self, boolean): + boolean.static_type = 'Bool' + return True + + @visitor.when(Interger) + def visit(self, interger): + interger.static_type = 'Int' + return True + + @visitor.when(String) + def visit(self, string): + string.static_type = 'String' + return True + + + + @visitor.when(Conditional) + def visit(self, cond): + if not self.visit(cond.if_expression): + return False + if not self.visit(cond.then_expression): + return False + if not self.visit(cond.else_expression): + return False + + if cond.if_expression.static_type != 'Bool': + self.error.append("({}, {}) - TypeError: Predicate of 'if' does not have type Bool.".format(cond.line, cond.index)) + return False + + thenType = cond.then_expression.static_type + elseType = cond.else_expression.static_type + + cond.static_type = self.lca(thenType, elseType) + return True + + @visitor.when(Loop) + def visit(self, loop): + + if not self.visit(loop.while_expression): + return False + + if not self.visit(loop.loop_expression): + return False + + if loop.while_expression.static_type != 'Bool': + self.error.append('({}, {}) - TypeError: Loop condition does not have type Bool.'.format(loop.line, loop.index)) + return False + + loop.static_type = 'Object' + + return True + + + + @visitor.when(LetVar) + def visit(self, let): + + for item in let.declarations: + if not self.visit(item): + return False + self.local_variables.append((item.id, item.static_type)) + + # if item.expr is None: + # local_variables.append((item.id,item.type)) + # else: + # if not visit(item.expr): + # return False + #local_variables.append((item.id,item.type)) + + if not self.visit(let.in_expression): + return False + + n = len(let.declarations) + m = len(self.local_variables) + + for i in range(n): + self.local_variables.pop(m - i - 1) + + let.static_type = let.in_expression.static_type + + return True + + + + @visitor.when(Assign) + def visit(self, assign): + + if not self.visit(assign.expression): + return False + + id_declared = False + id_type = None + + #verificar si esta declarado + if assign.id == 'self': + self.error.append("({}, {}) - SemanticError: Cannot assign to 'self'.".format(assign.line, assign.index)) + return False + else: + n = len(self.local_variables) - 1 + for i in range(n, -1, -1): + local_id, local_type = self.local_variables[i] + if local_id == assign.id: + id_declared = True + id_type = local_type + break + if not id_declared: + if not self.current_method is None: + for args_id, args_type in self.classmethods[self.current_class][self.current_method][0]: + if args_id == assign.id: + id_declared = True + id_type = args_type + break + if not id_declared: + for _var in self.class_attrs[self.current_class]: + attr_id = _var.id + attr_type = _var.type + if attr_id == assign.id: + id_declared = True + id_type = attr_type + break + + if not id_declared: + #print('error: variable no declarada') + return False + + if not self.conforms[assign.expression.static_type].__contains__(id_type): + #print('error: el tipo de la variable no se corresponde con el de la expression') + return False + + assign.static_type = assign.expression.static_type + return True + + + + + @visitor.when(Attribute) + def visit(self, attr): + + if attr.id == 'self': + self.error.append('({}, {}) - SemanticError: is an error to assign to self or to bind self in a let, a case, or as a formal parameter. It is also illegal to have attributes named self.'.format(attr.line, attr.index)) + return False + + if not self.classmethods.__contains__(attr.type): + self.error.append('({}, {}) - TypeError: Class {} of declaration of {} is undefined.'.format(attr.line, attr.index, attr.type, attr.id)) + return False + if not self.visit(attr.expr): + return False + if not self.conforms[attr.expr.static_type].__contains__(attr.type): + self.error.append('({}, {}) - TypeError: Inferred type {} of initialization of {} does not conform to declared type {}.'.format(attr.line, attr.index, attr.expr.static_type, attr.id, attr.type)) + return False + + attr.static_type = attr.type + return True + + @visitor.when(Var) + def visit(self, var): + + if var.id == 'self': + self.error.append('({}, {}) - SemanticError: is an error to assign to self or to bind self in a let, a case, or as a formal parameter. It is also illegal to have attributes named self.'.format(var.line, var.index)) + return False + + if not self.classmethods.__contains__(var.type): + self.error.append('({}, {}) - TypeError: Class {} of declaration of {} is undefined.'.format(var.line, var.index, var.type, var.id)) + return False + + var.static_type = var.type + return True + + + @visitor.when(Dispatch) + def visit(self, dispatch): + paramsTypes = [] + if not dispatch.parameters is None: + for e in dispatch.parameters: + if not self.visit(e): + return False + paramsTypes.append(e.static_type) + if dispatch.left_expression is None: + if not self.classmethods[self.current_class].__contains__(dispatch.func_id): + self.error.append('({}, {}) - AttributeError: Dispatch to undefined method {}.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + officialArgsType = [x[1] for x in self.classmethods[self.current_class][dispatch.func_id][0]] + _static_type = self.classmethods[self.current_class][dispatch.func_id][1] + else: + if not self.visit(dispatch.left_expression): + return False + if not self.classmethods[dispatch.left_expression.static_type].__contains__(dispatch.func_id): + self.error.append('({}, {}) - AttributeError: Dispatch to undefined method {}.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + officialArgsType = [x[1] for x in self.classmethods[dispatch.left_expression.static_type][dispatch.func_id][0]] + _static_type = self.classmethods[dispatch.left_expression.static_type][dispatch.func_id][1] + + if len(officialArgsType) != len(paramsTypes): + self.error.append('({}, {}) - SemanticError: Method {} called with wrong number of arguments.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + + _len = len(paramsTypes) + for i in range(_len): + if not self.conforms[paramsTypes[i]].__contains__(officialArgsType[i]): + self.error.append('({}, {}) - TypeError: In call of method {}, of parameters does not conform to declared type.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + dispatch.static_type = _static_type + return True + + + @visitor.when(StaticDispatch) + def visit(self, static_dispatch): + paramsTypes = [] + if not static_dispatch.parameters is None: + for e in static_dispatch.parameters: + if not self.visit(e): + return False + paramsTypes.append(e.static_type) + + if not self.visit(static_dispatch.left_expression): + return False + + if not self.conforms[static_dispatch.left_expression.static_type].__contains__(static_dispatch.parent_type): + self.error.append('({}, {}) - TypeError: Expression type {} does not conform to declared static dispatch type {}.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.left_expression.static_type, static_dispatch.parent_type)) + return False + + if not self.classmethods_original[static_dispatch.parent_type].__contains__(static_dispatch.func_id): + self.error.append('({}, {}) - AttributeError: Dispatch to undefined method {}.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.func_id)) + return False + + officialArgsType = [x[1] for x in self.classmethods[static_dispatch.left_expression.static_type][static_dispatch.func_id][0]] + if len(officialArgsType) != len(paramsTypes): + self.error.append('({}, {}) - SemanticError: Method {} called with wrong number of arguments.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.func_id)) + return False + _len = len(paramsTypes) + for i in range(_len): + if not self.conforms[paramsTypes[i]].__contains__(officialArgsType[i]): + self.error.append('({}, {}) - TypeError: In call of method {}, of parameters does not conform to declared type.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.func_id)) + return False + + static_dispatch.static_type = self.classmethods[static_dispatch.left_expression.static_type][static_dispatch.func_id][1] + return True + + @visitor.when(Branch) + def visit(self, branch): + if not self.visit(branch.expr): + return False + branch.static_type = branch.expr.static_type + return True + + @visitor.when(Case) + def visit(self, case): + + if not self.visit(case.case_expression): + return False + + branchTypeSet = set([]) + for branch in case.implications: + if branchTypeSet.__contains__(branch.var.type): + self.error.append('({}, {}) - SemanticError: Duplicate branch {} in case statement.'.format(branch.line, branch.index, branch.var.type)) + return False + branchTypeSet.add(branch.var.type) + if not self.classmethods.__contains__(branch.var.type): + self.error.append('({}, {}) - TypeError: Class {} of case branch is undefined.'.format(branch.line, branch.index, branch.var.type)) + return False + + self.local_variables.append((branch.var.id, branch.var.type)) + if not self.visit(branch): + return False + n = len(self.local_variables) - 1 + self.local_variables.pop(n) + + static_type = case.implications[0].static_type + for branch in case.implications[1:]: + static_type = self.lca(static_type, branch.static_type) + + case.static_type = static_type + return True diff --git a/src/tools.py b/src/tools.py new file mode 100644 index 00000000..ec7260e8 --- /dev/null +++ b/src/tools.py @@ -0,0 +1,29 @@ +def dfs_visit(G, v, t, c, d): + t += 1 + d[v] = t + c[v] = 1 + for u in G[v]: + if not G.__contains__(u): + continue + if c[u] == 0: + if dfs_visit(G, u, t, c, d): + return True + elif c[u] == 1: + return True + c[v] = 2 + return False + +def dfs(G, classes): + '''retorna true si hay ciclo''' + color = {} + d = {} + for c in classes: + color[c] = 0 + d[c] = -1 + time = 0 + for v in G.keys(): + if color[v] == 0: + if dfs_visit(G, v, time, color, d): + return True + return False + diff --git a/src/visitor.py b/src/visitor.py new file mode 100644 index 00000000..765159f6 --- /dev/null +++ b/src/visitor.py @@ -0,0 +1,76 @@ +# The MIT License (MIT) +# +# Copyright (c) 2019 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = iter(t) + return [t[k](*args, **kw) for k in ks if issub(typ, k)] + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) \ No newline at end of file diff --git a/tests/codegen/arith_input.txt b/tests/codegen/arith_input.txt new file mode 100644 index 00000000..83e05b1e --- /dev/null +++ b/tests/codegen/arith_input.txt @@ -0,0 +1,13 @@ +a +1 +b +c +0 +d +e +f +g +h +j +5 +q diff --git a/tests/codegen/arith_output.txt b/tests/codegen/arith_output.txt new file mode 100644 index 00000000..44b4ce73 --- /dev/null +++ b/tests/codegen/arith_output.txt @@ -0,0 +1,158 @@ +number 0 is even! +Class type is now A + + To add a number to 0 ...enter a: + To negate 0 ...enter b: + To find the difference between 0 and another number...enter c: + To find the factorial of 0 ...enter d: + To square 0 ...enter e: + To cube 0 ...enter f: + To find out if 0 is a multiple of 3...enter g: + To divide 0 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + + +Please enter a number... number 1 is odd! +Class type is now B + + To add a number to 1 ...enter a: + To negate 1 ...enter b: + To find the difference between 1 and another number...enter c: + To find the factorial of 1 ...enter d: + To square 1 ...enter e: + To cube 1 ...enter f: + To find out if 1 is a multiple of 3...enter g: + To divide 1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number -1 is odd! +Class type is now C + + To add a number to -1 ...enter a: + To negate -1 ...enter b: + To find the difference between -1 and another number...enter c: + To find the factorial of -1 ...enter d: + To square -1 ...enter e: + To cube -1 ...enter f: + To find out if -1 is a multiple of 3...enter g: + To divide -1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + + +Please enter a number... number 1 is odd! +Class type is now D + + To add a number to 1 ...enter a: + To negate 1 ...enter b: + To find the difference between 1 and another number...enter c: + To find the factorial of 1 ...enter d: + To square 1 ...enter e: + To cube 1 ...enter f: + To find out if 1 is a multiple of 3...enter g: + To divide 1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 1 is odd! +Class type is now E + + To add a number to 1 ...enter a: + To negate 1 ...enter b: + To find the difference between 1 and another number...enter c: + To find the factorial of 1 ...enter d: + To square 1 ...enter e: + To cube 1 ...enter f: + To find out if 1 is a multiple of 3...enter g: + To divide 1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 1 is odd! +Class type is now E + + To add a number to 1 ...enter a: + To negate 1 ...enter b: + To find the difference between 1 and another number...enter c: + To find the factorial of 1 ...enter d: + To square 1 ...enter e: + To cube 1 ...enter f: + To find out if 1 is a multiple of 3...enter g: + To divide 1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 1 is odd! +Class type is now E + + To add a number to 1 ...enter a: + To negate 1 ...enter b: + To find the difference between 1 and another number...enter c: + To find the factorial of 1 ...enter d: + To square 1 ...enter e: + To cube 1 ...enter f: + To find out if 1 is a multiple of 3...enter g: + To divide 1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 1 is not divisible by 3. +number 1 is odd! +Class type is now E + + To add a number to 1 ...enter a: + To negate 1 ...enter b: + To find the difference between 1 and another number...enter c: + To find the factorial of 1 ...enter d: + To square 1 ...enter e: + To cube 1 ...enter f: + To find out if 1 is a multiple of 3...enter g: + To divide 1 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 1 is equal to 0 times 8 with a remainder of 1 +number 0 is even! +Class type is now A + + To add a number to 0 ...enter a: + To negate 0 ...enter b: + To find the difference between 0 and another number...enter c: + To find the factorial of 0 ...enter d: + To square 0 ...enter e: + To cube 0 ...enter f: + To find out if 0 is a multiple of 3...enter g: + To divide 0 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 0 is even! +Class type is now A + + To add a number to 0 ...enter a: + To negate 0 ...enter b: + To find the difference between 0 and another number...enter c: + To find the factorial of 0 ...enter d: + To square 0 ...enter e: + To cube 0 ...enter f: + To find out if 0 is a multiple of 3...enter g: + To divide 0 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + +number 0 is even! +Class type is now A + + To add a number to 0 ...enter a: + To negate 0 ...enter b: + To find the difference between 0 and another number...enter c: + To find the factorial of 0 ...enter d: + To square 0 ...enter e: + To cube 0 ...enter f: + To find out if 0 is a multiple of 3...enter g: + To divide 0 by 8...enter h: + To get a new number...enter j: + To quit...enter q: + diff --git a/tests/codegen/atoi2.cl b/tests/codegen/atoi2.cl deleted file mode 100644 index 577aa29f..00000000 --- a/tests/codegen/atoi2.cl +++ /dev/null @@ -1,92 +0,0 @@ -class JustThere { -- class can have no features. -}; - -class A2I { - - c2i(char : String) : Int { - if char = "0" then 0 else - if char = "1" then 1 else - if char = "2" then 2 else - if char = "3" then 3 else - if char = "4" then 4 else - if char = "5" then 5 else - if char = "6" then 6 else - if char = "7" then 7 else - if char = "8" then 8 else - if char = "9" then 9 else - { abort(); 0; } -- Here the formal list is optional. - fi fi fi fi fi fi fi fi fi fi - }; - - - i2c(i : Int) : String { - if i = 0 then "0" else - if i = 1 then "1" else - if i = 2 then "2" else - if i = 3 then "3" else - if i = 4 then "4" else - if i = 5 then "5" else - if i = 6 then "6" else - if i = 7 then "7" else - if i = 8 then "8" else - if i = 9 then "9" else - { abort(); ""; } -- demonstrates an expression block - fi fi fi fi fi fi fi fi fi fi - }; - - a2i(s : String) : Int { - if s.length() = 0 then 0 else - if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else - if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else - a2i_aux(s) - fi fi fi - }; - - a2i_aux(s : String) : Int { - (let int : Int <- 0 in - { - (let j : Int <- s.length() in - (let i : Int <- 0 in - while i < j loop - { - int <- int * 10 + c2i(s.substr(i,1)); -- demonstrates dispatch - i <- i + 1; - } - pool - ) - ); - int; - } - ) - }; - - i2a(i : Int) : String { - if i = 0 then "0" else - if 0 < i then i2a_aux(i) else - "-".concat(i2a_aux(i * ~1)) - fi fi - }; - - - i2a_aux(i : Int) : String { - if i = 0 then "" else - (let next : Int <- i / 10 in - i2a_aux(next).concat(i2c(i - next * 10)) - ) - fi - }; - -}; - -class Main inherits IO { - main () : Object { - let a : Int <- (new A2I).a2i("678987"), - b : String <- (new A2I).i2a(678987) in -- the let expression. Translated to let a: ... in let b: ... in expr. - { - out_int(a) ; - out_string(" == ") ; - out_string(b) ; - out_string("\n"); - } - } ; -} ; diff --git a/tests/codegen/atoi_input.txt b/tests/codegen/atoi_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/atoi_output.txt b/tests/codegen/atoi_output.txt new file mode 100644 index 00000000..51b815a4 --- /dev/null +++ b/tests/codegen/atoi_output.txt @@ -0,0 +1 @@ +678987 == 678987 diff --git a/tests/codegen/book_list_input.txt b/tests/codegen/book_list_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/book_list_output.txt b/tests/codegen/book_list_output.txt new file mode 100644 index 00000000..3408320b --- /dev/null +++ b/tests/codegen/book_list_output.txt @@ -0,0 +1,7 @@ +title: The Top 100 CD_ROMs +author: Ulanoff +periodical: PC Magazine +- dynamic type was Article - +title: Compilers, Principles, Techniques, and Tools +author: Aho, Sethi, and Ullman +- dynamic type was Book - diff --git a/tests/codegen/cells_input.txt b/tests/codegen/cells_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/cells_output.txt b/tests/codegen/cells_output.txt new file mode 100644 index 00000000..6304902c --- /dev/null +++ b/tests/codegen/cells_output.txt @@ -0,0 +1,21 @@ + X +........XXX........ +.......X...X....... +......XXX.XXX...... +.....X.......X..... +....XXX.....XXX.... +...X...X...X...X... +..XXX.XXX.XXX.XXX.. +.X...............X. +XXX.............XXX +...X...........X... +..XXX.........XXX.. +.X...X.......X...X. +XXX.XXX.....XXX.XXX +.......X...X....... +......XXX.XXX...... +.....X.......X..... +....XXX.....XXX.... +...X...X...X...X... +..XXX.XXX.XXX.XXX.. +.X...............X. diff --git a/tests/codegen/complex_input.txt b/tests/codegen/complex_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/complex_output.txt b/tests/codegen/complex_output.txt new file mode 100644 index 00000000..18b77c1f --- /dev/null +++ b/tests/codegen/complex_output.txt @@ -0,0 +1 @@ +=) diff --git a/tests/codegen/fib_input.txt b/tests/codegen/fib_input.txt new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/tests/codegen/fib_input.txt @@ -0,0 +1 @@ +10 diff --git a/tests/codegen/fib_output.txt b/tests/codegen/fib_output.txt new file mode 100644 index 00000000..d402da6a --- /dev/null +++ b/tests/codegen/fib_output.txt @@ -0,0 +1,2 @@ +Enter n to find nth fibonacci number! +89 diff --git a/tests/codegen/graph_input.txt b/tests/codegen/graph_input.txt new file mode 100644 index 00000000..b67d9021 --- /dev/null +++ b/tests/codegen/graph_input.txt @@ -0,0 +1,5 @@ +1 2,100 +2 3,200 1,150 +3 2,10 +4 3,55 5,100 +5 1,1 2,2 3,3 4,4 5,5 diff --git a/tests/codegen/graph_output.txt b/tests/codegen/graph_output.txt new file mode 100644 index 00000000..ef446522 --- /dev/null +++ b/tests/codegen/graph_output.txt @@ -0,0 +1,7 @@ +5 (5,5)5 (5,4)4 (5,3)3 (5,2)2 (5,1)1 +4 (4,5)100 (4,3)55 +3 (3,2)10 +2 (2,1)150 (2,3)200 +1 (1,2)100 + + (5,5)5 (5,4)4 (5,3)3 (5,2)2 (5,1)1 (4,5)100 (4,3)55 (3,2)10 (2,1)150 (2,3)200 (1,2)100 diff --git a/tests/codegen/hairyscary_input.txt b/tests/codegen/hairyscary_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/hairyscary_output.txt b/tests/codegen/hairyscary_output.txt new file mode 100644 index 00000000..8985c22f --- /dev/null +++ b/tests/codegen/hairyscary_output.txt @@ -0,0 +1 @@ +17141611714163171416511714161171416317141653117141611714163171416511714161171416317141653171416117141631714165171416 \ No newline at end of file diff --git a/tests/codegen/hello_world_input.txt b/tests/codegen/hello_world_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/hello_world_output.txt b/tests/codegen/hello_world_output.txt new file mode 100644 index 00000000..349db2bf --- /dev/null +++ b/tests/codegen/hello_world_output.txt @@ -0,0 +1 @@ +Hello, World. diff --git a/tests/codegen/helloworld.cl b/tests/codegen/helloworld.cl deleted file mode 100644 index 61d42108..00000000 --- a/tests/codegen/helloworld.cl +++ /dev/null @@ -1,6 +0,0 @@ -class Main { - main():IO { - new IO.out_string("Hello world!\n") - }; -}; - diff --git a/tests/codegen/io_input.txt b/tests/codegen/io_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/io_output.txt b/tests/codegen/io_output.txt new file mode 100644 index 00000000..f846f596 --- /dev/null +++ b/tests/codegen/io_output.txt @@ -0,0 +1,5 @@ +A: Hello world +B: Hello world +C: Hello world +D: Hello world +Done. diff --git a/tests/codegen/life_input.txt b/tests/codegen/life_input.txt new file mode 100644 index 00000000..07e01672 --- /dev/null +++ b/tests/codegen/life_input.txt @@ -0,0 +1,66 @@ +y +1 +n +y +2 +n +y +3 +n +y +4 +n +y +5 +n +y +6 +n +y +7 +n +y +8 +n +y +9 +n +y +10 +n +y +11 +n +y +12 +n +y +13 +n +y +14 +n +y +15 +n +y +16 +n +y +17 +n +y +18 +n +y +19 +n +y +20 +n +y +21 +y +y +n +n \ No newline at end of file diff --git a/tests/codegen/life_output.txt b/tests/codegen/life_output.txt new file mode 100644 index 00000000..5a9b9f73 --- /dev/null +++ b/tests/codegen/life_output.txt @@ -0,0 +1,778 @@ +Welcome to the Game of Life. +There are many initial states to choose from. + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + XX +XXXX +XXXX + XX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + X + X + X + X +X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X + X + X + X + X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X X + X X + X + X X +X X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X + X + X + X +X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + X + X + X + X + X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X X + X X +X X + + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + X X +X X + X X + + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X X + X X + X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + X + X X +X X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X X X + X X +X X X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +XXXXX +XXXXX +XXXXX +XXXXX +XXXXX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +XXXXX + X + X + X + X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + X + X +XXXXX + X + X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +X X + X X X + X X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + X X + X X X +X X + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +XXXX +X +X +XXXX +X +X +XXXX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + +XXX + X + X + X + X + X +XXX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + XX +X X +X X + XX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + XX +X X +X X + XX +X X +X X + XX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: +Please chose a number: + 1: A cross + 2: A slash from the upper left to lower right + 3: A slash from the upper right to lower left + 4: An X + 5: A greater than sign + 6: A less than sign + 7: Two greater than signs + 8: Two less than signs + 9: A 'V' + 10: An inverse 'V' + 11: Numbers 9 and 10 combined + 12: A full grid + 13: A 'T' + 14: A plus '+' + 15: A 'W' + 16: An 'M' + 17: An 'E' + 18: A '3' + 19: An 'O' + 20: An '8' + 21: An 'S' +Your choice => + + XXX +X +X + XX + X + X +XXX + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + +-XX- +X-X- +X--- +-XX- +---X +-X-X +-XX- + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + +-XX- +X-X- +X-X- +-XX- +-X-X +-X-X +-XX- + +Would you like to continue with the next generation? +Please use lowercase y or n for your answer [y]: + + +Would you like to choose a background pattern? +Please use lowercase y or n for your answer [n]: \ No newline at end of file diff --git a/tests/codegen/list_input.txt b/tests/codegen/list_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/list_output.txt b/tests/codegen/list_output.txt new file mode 100644 index 00000000..fca72490 --- /dev/null +++ b/tests/codegen/list_output.txt @@ -0,0 +1,5 @@ +5 4 3 2 1 +4 3 2 1 +3 2 1 +2 1 +1 diff --git a/tests/codegen/new_complex_input.txt b/tests/codegen/new_complex_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/new_complex_output.txt b/tests/codegen/new_complex_output.txt new file mode 100644 index 00000000..0e8da112 --- /dev/null +++ b/tests/codegen/new_complex_output.txt @@ -0,0 +1,2 @@ +=) +=) diff --git a/tests/codegen/palindrome_input.txt b/tests/codegen/palindrome_input.txt new file mode 100644 index 00000000..8e1b6414 --- /dev/null +++ b/tests/codegen/palindrome_input.txt @@ -0,0 +1 @@ +anitalabalatina diff --git a/tests/codegen/palindrome_output.txt b/tests/codegen/palindrome_output.txt new file mode 100644 index 00000000..7a009595 --- /dev/null +++ b/tests/codegen/palindrome_output.txt @@ -0,0 +1,2 @@ +enter a string +that was a palindrome diff --git a/tests/codegen/primes_input.txt b/tests/codegen/primes_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/primes_output.txt b/tests/codegen/primes_output.txt new file mode 100644 index 00000000..a4d0fcb3 --- /dev/null +++ b/tests/codegen/primes_output.txt @@ -0,0 +1,96 @@ +2 is trivially prime. +3 is prime. +5 is prime. +7 is prime. +11 is prime. +13 is prime. +17 is prime. +19 is prime. +23 is prime. +29 is prime. +31 is prime. +37 is prime. +41 is prime. +43 is prime. +47 is prime. +53 is prime. +59 is prime. +61 is prime. +67 is prime. +71 is prime. +73 is prime. +79 is prime. +83 is prime. +89 is prime. +97 is prime. +101 is prime. +103 is prime. +107 is prime. +109 is prime. +113 is prime. +127 is prime. +131 is prime. +137 is prime. +139 is prime. +149 is prime. +151 is prime. +157 is prime. +163 is prime. +167 is prime. +173 is prime. +179 is prime. +181 is prime. +191 is prime. +193 is prime. +197 is prime. +199 is prime. +211 is prime. +223 is prime. +227 is prime. +229 is prime. +233 is prime. +239 is prime. +241 is prime. +251 is prime. +257 is prime. +263 is prime. +269 is prime. +271 is prime. +277 is prime. +281 is prime. +283 is prime. +293 is prime. +307 is prime. +311 is prime. +313 is prime. +317 is prime. +331 is prime. +337 is prime. +347 is prime. +349 is prime. +353 is prime. +359 is prime. +367 is prime. +373 is prime. +379 is prime. +383 is prime. +389 is prime. +397 is prime. +401 is prime. +409 is prime. +419 is prime. +421 is prime. +431 is prime. +433 is prime. +439 is prime. +443 is prime. +449 is prime. +457 is prime. +461 is prime. +463 is prime. +467 is prime. +479 is prime. +487 is prime. +491 is prime. +499 is prime. +Abort called from class String diff --git a/tests/codegen/print-cool_input.txt b/tests/codegen/print-cool_input.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/codegen/print-cool_output.txt b/tests/codegen/print-cool_output.txt new file mode 100644 index 00000000..2b58f898 --- /dev/null +++ b/tests/codegen/print-cool_output.txt @@ -0,0 +1 @@ +cool diff --git a/tests/codegen/sort-list_input.txt b/tests/codegen/sort-list_input.txt new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/tests/codegen/sort-list_input.txt @@ -0,0 +1 @@ +10 diff --git a/tests/codegen/sort-list_output.txt b/tests/codegen/sort-list_output.txt new file mode 100644 index 00000000..9878d57e --- /dev/null +++ b/tests/codegen/sort-list_output.txt @@ -0,0 +1,10 @@ +How many numbers to sort? 0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/tests/codegen/test.cl b/tests/codegen/test.cl deleted file mode 100755 index 9c2e0fd8..00000000 --- a/tests/codegen/test.cl +++ /dev/null @@ -1,19 +0,0 @@ -class Main inherits IO { - - main () : Object { - { - let x:A <- new B in out_string( x.f().m() ); - let x:A <- new A in out_string( x.f().m() ); - } - - }; -}; - -class A { - m () : String { "A" }; - f () : A { new A }; -}; - -class B inherits A { - m () : String { "B" }; -}; diff --git a/tests/codegen_test.py b/tests/codegen_test.py index 9c41f826..48df768f 100644 --- a/tests/codegen_test.py +++ b/tests/codegen_test.py @@ -1,15 +1,17 @@ import pytest import os -from utils import compare_errors +from utils import compare_outputs tests_dir = __file__.rpartition('/')[0] + '/codegen/' -tests = [(tests_dir + file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -@pytest.mark.run(order=4) -@pytest.mark.lexer -@pytest.mark.parser -@pytest.mark.semantic +# @pytest.mark.lexer +# @pytest.mark.parser +# @pytest.mark.semantic +@pytest.mark.codegen @pytest.mark.ok +@pytest.mark.run(order=4) @pytest.mark.parametrize("cool_file", tests) def test_codegen(compiler_path, cool_file): - compare_errors(compiler_path, cool_file, None) \ No newline at end of file + compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ + tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file diff --git a/tests/lexer/comment1.cl b/tests/lexer/comment1.cl new file mode 100644 index 00000000..69533f23 --- /dev/null +++ b/tests/lexer/comment1.cl @@ -0,0 +1,55 @@ +--Any characters between two dashes “--” and the next newline +--(or EOF, if there is no next newline) are treated as comments + +(*(*(* +Comments may also be written by enclosing +text in (∗ . . . ∗). The latter form of comment may be nested. +Comments cannot cross file boundaries. +*)*)*) + +class Error() { + + (* There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. + There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. \ No newline at end of file diff --git a/tests/lexer/comment1_error.txt b/tests/lexer/comment1_error.txt new file mode 100644 index 00000000..9fd7b8d6 --- /dev/null +++ b/tests/lexer/comment1_error.txt @@ -0,0 +1 @@ +(55, 46) - LexicographicError: EOF in comment diff --git a/tests/lexer/iis1.cl b/tests/lexer/iis1.cl new file mode 100644 index 00000000..12cb52be --- /dev/null +++ b/tests/lexer/iis1.cl @@ -0,0 +1,111 @@ +(* Integers, Identifiers, and Special Notation *) + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +5! = 120, 2 + 2 = 5 or E = mc2; p + 1 @ p = 1: for x in range(len(b)) +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +class Class if then else fi testing Testing ~007agent_bond james_007B0N3SS___ +loop pool while tRuE or noT faLsE let in case of ESAC + +(* +#3 INT_CONST 0007 +#3 INT_CONST 123 +#3 '+' +#3 INT_CONST 1 +#3 '-' +#3 INT_CONST 1 +#3 '+' +#3 INT_CONST 90 +#3 '-' +#3 INT_CONST 09 +#3 '+' +#3 INT_CONST 11113 +#3 '-' +#3 INT_CONST 4 +#3 OBJECTID r +#3 '*' +#3 OBJECTID a +#3 '*' +#3 OBJECTID self +#3 '*' +#3 OBJECTID c +#3 '+' +#3 '+' +#4 INT_CONST 5 +#4 ERROR "!" +#4 '=' +#4 INT_CONST 120 +#4 ',' +#4 INT_CONST 2 +#4 '+' +#4 INT_CONST 2 +#4 '=' +#4 INT_CONST 5 +#4 OBJECTID or +#4 TYPEID E +#4 '=' +#4 OBJECTID mc2 +#4 ';' +#4 OBJECTID p +#4 '+' +#4 INT_CONST 1 +#4 '@' +#4 OBJECTID p +#4 '=' +#4 INT_CONST 1 +#4 ':' +#4 OBJECTID for +#4 OBJECTID x +#4 IN +#4 OBJECTID range +#4 '(' +#4 OBJECTID len +#4 '(' +#4 OBJECTID b +#4 ')' +#4 ')' +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#6 CLASS +#6 CLASS +#6 IF +#6 THEN +#6 ELSE +#6 FI +#6 OBJECTID testing +#6 TYPEID Testing +#6 '~' +#6 INT_CONST 007 +#6 OBJECTID agent_bond +#6 OBJECTID james_007B0N3SS___ +#7 LOOP +#7 POOL +#7 WHILE +#7 BOOL_CONST true +#7 OBJECTID or +#7 NOT +#7 BOOL_CONST false +#7 LET +#7 IN +#7 CASE +#7 OF +#7 ESAC +*) \ No newline at end of file diff --git a/tests/lexer/iis1_error.txt b/tests/lexer/iis1_error.txt new file mode 100644 index 00000000..9e6d66ca --- /dev/null +++ b/tests/lexer/iis1_error.txt @@ -0,0 +1 @@ +(4, 2) - LexicographicError: ERROR "!" diff --git a/tests/lexer/iis2.cl b/tests/lexer/iis2.cl new file mode 100644 index 00000000..9b25715d --- /dev/null +++ b/tests/lexer/iis2.cl @@ -0,0 +1,120 @@ +(* Integers, Identifiers, and Special Notation *) + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +loop pool while tRuE or noT faLsE let in case of ESAC + +factorial(5) = 120, 2 + 2 = 5? or E = mc2; p + 1 resto p = 1: (@ for x in range(len(b))) + +(* +#3 INT_CONST 0007 +#3 INT_CONST 123 +#3 '+' +#3 INT_CONST 1 +#3 '-' +#3 INT_CONST 1 +#3 '+' +#3 INT_CONST 90 +#3 '-' +#3 INT_CONST 09 +#3 '+' +#3 INT_CONST 11113 +#3 '-' +#3 INT_CONST 4 +#3 OBJECTID r +#3 '*' +#3 OBJECTID a +#3 '*' +#3 OBJECTID self +#3 '*' +#3 OBJECTID c +#3 '+' +#3 '+' +#4 CLASS +#4 CLASS +#4 IF +#4 THEN +#4 ELSE +#4 FI +#4 OBJECTID testing +#4 TYPEID Testing +#4 '~' +#4 INT_CONST 007 +#4 OBJECTID agent_bond +#4 OBJECTID james_007bones___ +#7 NEW +#7 '/' +#7 ASSIGN +#7 '<' +#7 LE +#7 DARROW +#7 '{' +#7 '(' +#7 TYPEID Int +#7 ':' +#7 TYPEID Objet +#7 ',' +#7 TYPEID Bool +#7 ';' +#7 TYPEID String +#7 '.' +#7 OBJECTID string +#7 TYPEID SELF_TYPE +#7 ISVOID +#7 '}' +#7 ')' +#8 LOOP +#8 POOL +#8 WHILE +#8 BOOL_CONST true +#8 OBJECTID or +#8 NOT +#8 BOOL_CONST false +#8 LET +#8 IN +#8 CASE +#8 OF +#8 ESAC +#10 OBJECTID factorial +#10 '(' +#10 INT_CONST 5 +#10 ')' +#10 '=' +#10 INT_CONST 120 +#10 ',' +#10 INT_CONST 2 +#10 '+' +#10 INT_CONST 2 +#10 '=' +#10 INT_CONST 5 +#10 ERROR "?" +#10 OBJECTID or +#10 TYPEID E +#10 '=' +#10 OBJECTID mc2 +#10 ';' +#10 OBJECTID p +#10 '+' +#10 INT_CONST 1 +#10 OBJECTID resto +#10 OBJECTID p +#10 '=' +#10 INT_CONST 1 +#10 ':' +#10 '(' +#10 '@' +#10 OBJECTID for +#10 OBJECTID x +#10 IN +#10 OBJECTID range +#10 '(' +#10 OBJECTID len +#10 '(' +#10 OBJECTID b +#10 ')' +#10 ')' +#10 ')' +*) \ No newline at end of file diff --git a/tests/lexer/iis2_error.txt b/tests/lexer/iis2_error.txt new file mode 100644 index 00000000..922391a9 --- /dev/null +++ b/tests/lexer/iis2_error.txt @@ -0,0 +1 @@ +(10, 30) - LexicographicError: ERROR "?" diff --git a/tests/lexer/iis3.cl b/tests/lexer/iis3.cl new file mode 100644 index 00000000..0b965dde --- /dev/null +++ b/tests/lexer/iis3.cl @@ -0,0 +1,121 @@ +(* Integers, Identifiers, and Special Notation *) + +factorial(5) = 120, 2 + 2 = 5 or E = mc^2; p + 1 @ p = 1: z for x in range(len(b))) + +loop pool while tRuE or noT faLsE let in case of ESAC + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) + + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + +(* +#3 OBJECTID factorial +#3 '(' +#3 INT_CONST 5 +#3 ')' +#3 '=' +#3 INT_CONST 120 +#3 ',' +#3 INT_CONST 2 +#3 '+' +#3 INT_CONST 2 +#3 '=' +#3 INT_CONST 5 +#3 OBJECTID or +#3 TYPEID E +#3 '=' +#3 OBJECTID mc +#3 ERROR "^" +#3 INT_CONST 2 +#3 ';' +#3 OBJECTID p +#3 '+' +#3 INT_CONST 1 +#3 '@' +#3 OBJECTID p +#3 '=' +#3 INT_CONST 1 +#3 ':' +#3 OBJECTID z +#3 OBJECTID for +#3 OBJECTID x +#3 IN +#3 OBJECTID range +#3 '(' +#3 OBJECTID len +#3 '(' +#3 OBJECTID b +#3 ')' +#3 ')' +#3 ')' +#5 LOOP +#5 POOL +#5 WHILE +#5 BOOL_CONST true +#5 OBJECTID or +#5 NOT +#5 BOOL_CONST false +#5 LET +#5 IN +#5 CASE +#5 OF +#5 ESAC +#7 NEW +#7 '/' +#7 ASSIGN +#7 '<' +#7 LE +#7 DARROW +#7 '{' +#7 '(' +#7 TYPEID Int +#7 ':' +#7 TYPEID Objet +#7 ',' +#7 TYPEID Bool +#7 ';' +#7 TYPEID String +#7 '.' +#7 OBJECTID string +#7 TYPEID SELF_TYPE +#7 ISVOID +#7 '}' +#7 ')' +#10 INT_CONST 0007 +#10 INT_CONST 123 +#10 '+' +#10 INT_CONST 1 +#10 '-' +#10 INT_CONST 1 +#10 '+' +#10 INT_CONST 90 +#10 '-' +#10 INT_CONST 09 +#10 '+' +#10 INT_CONST 11113 +#10 '-' +#10 INT_CONST 4 +#10 OBJECTID r +#10 '*' +#10 OBJECTID a +#10 '*' +#10 OBJECTID self +#10 '*' +#10 OBJECTID c +#10 '+' +#10 '+' +#11 CLASS +#11 CLASS +#11 IF +#11 THEN +#11 ELSE +#11 FI +#11 OBJECTID testing +#11 TYPEID Testing +#11 '~' +#11 INT_CONST 007 +#11 OBJECTID agent_bond +#11 OBJECTID james_007bones___ +*) \ No newline at end of file diff --git a/tests/lexer/iis3_error.txt b/tests/lexer/iis3_error.txt new file mode 100644 index 00000000..b001b6a7 --- /dev/null +++ b/tests/lexer/iis3_error.txt @@ -0,0 +1 @@ +(3, 40) - LexicographicError: ERROR "^" diff --git a/tests/lexer/iis4.cl b/tests/lexer/iis4.cl new file mode 100644 index 00000000..9e7a9cb6 --- /dev/null +++ b/tests/lexer/iis4.cl @@ -0,0 +1,120 @@ +(* Integers, Identifiers, and Special Notation *) + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ + +factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 % p = 1: @.@ for x in range(len(b))~ + + +loop pool while tRuE or noT faLsE let in case of ESAC +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + +(* +#3 NEW +#3 '/' +#3 ASSIGN +#3 '<' +#3 LE +#3 DARROW +#3 '{' +#3 '(' +#3 TYPEID Int +#3 ':' +#3 TYPEID Objet +#3 ',' +#3 TYPEID Bool +#3 ';' +#3 TYPEID String +#3 '.' +#3 OBJECTID string +#3 TYPEID SELF_TYPE +#3 ISVOID +#3 '}' +#3 ')' +#4 INT_CONST 0007 +#4 INT_CONST 123 +#4 '+' +#4 INT_CONST 1 +#4 '-' +#4 INT_CONST 1 +#4 '+' +#4 INT_CONST 90 +#4 '-' +#4 INT_CONST 09 +#4 '+' +#4 INT_CONST 11113 +#4 '-' +#4 INT_CONST 4 +#4 OBJECTID r +#4 '*' +#4 OBJECTID a +#4 '*' +#4 OBJECTID self +#4 '*' +#4 OBJECTID c +#4 '+' +#4 '+' +#6 OBJECTID factorial +#6 '(' +#6 INT_CONST 5 +#6 ')' +#6 '=' +#6 INT_CONST 120 +#6 ',' +#6 INT_CONST 2 +#6 '+' +#6 INT_CONST 2 +#6 '=' +#6 INT_CONST 5 +#6 OBJECTID or +#6 TYPEID E +#6 '=' +#6 OBJECTID mc2 +#6 ';' +#6 OBJECTID p +#6 '+' +#6 INT_CONST 1 +#6 ERROR "%" +#6 OBJECTID p +#6 '=' +#6 INT_CONST 1 +#6 ':' +#6 '@' +#6 '.' +#6 '@' +#6 OBJECTID for +#6 OBJECTID x +#6 IN +#6 OBJECTID range +#6 '(' +#6 OBJECTID len +#6 '(' +#6 OBJECTID b +#6 ')' +#6 ')' +#6 '~' +#9 LOOP +#9 POOL +#9 WHILE +#9 BOOL_CONST true +#9 OBJECTID or +#9 NOT +#9 BOOL_CONST false +#9 LET +#9 IN +#9 CASE +#9 OF +#9 ESAC +#10 CLASS +#10 CLASS +#10 IF +#10 THEN +#10 ELSE +#10 FI +#10 OBJECTID testing +#10 TYPEID Testing +#10 '~' +#10 INT_CONST 007 +#10 OBJECTID agent_bond +#10 OBJECTID james_007bones___ +*) \ No newline at end of file diff --git a/tests/lexer/iis4_error.txt b/tests/lexer/iis4_error.txt new file mode 100644 index 00000000..f24076a8 --- /dev/null +++ b/tests/lexer/iis4_error.txt @@ -0,0 +1 @@ +(6, 49) - LexicographicError: ERROR "!" diff --git a/tests/lexer/iis5.cl b/tests/lexer/iis5.cl new file mode 100644 index 00000000..d146c054 --- /dev/null +++ b/tests/lexer/iis5.cl @@ -0,0 +1,121 @@ +(* Integers, Identifiers, and Special Notation *) + + +loop pool while tRuE or noT faLsE let in case of ESAC +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + +factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 resto p = 1: [@.@ for x in range(len(b))] + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ + +(* +#4 LOOP +#4 POOL +#4 WHILE +#4 BOOL_CONST true +#4 OBJECTID or +#4 NOT +#4 BOOL_CONST false +#4 LET +#4 IN +#4 CASE +#4 OF +#4 ESAC +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#6 CLASS +#6 CLASS +#6 IF +#6 THEN +#6 ELSE +#6 FI +#6 OBJECTID testing +#6 TYPEID Testing +#6 '~' +#6 INT_CONST 007 +#6 OBJECTID agent_bond +#6 OBJECTID james_007bones___ +#8 OBJECTID factorial +#8 '(' +#8 INT_CONST 5 +#8 ')' +#8 '=' +#8 INT_CONST 120 +#8 ',' +#8 INT_CONST 2 +#8 '+' +#8 INT_CONST 2 +#8 '=' +#8 INT_CONST 5 +#8 OBJECTID or +#8 TYPEID E +#8 '=' +#8 OBJECTID mc2 +#8 ';' +#8 OBJECTID p +#8 '+' +#8 INT_CONST 1 +#8 OBJECTID resto +#8 OBJECTID p +#8 '=' +#8 INT_CONST 1 +#8 ':' +#8 ERROR "[" +#8 '@' +#8 '.' +#8 '@' +#8 OBJECTID for +#8 OBJECTID x +#8 IN +#8 OBJECTID range +#8 '(' +#8 OBJECTID len +#8 '(' +#8 OBJECTID b +#8 ')' +#8 ')' +#8 ERROR "]" +#10 INT_CONST 0007 +#10 INT_CONST 123 +#10 '+' +#10 INT_CONST 1 +#10 '-' +#10 INT_CONST 1 +#10 '+' +#10 INT_CONST 90 +#10 '-' +#10 INT_CONST 09 +#10 '+' +#10 INT_CONST 11113 +#10 '-' +#10 INT_CONST 4 +#10 OBJECTID r +#10 '*' +#10 OBJECTID a +#10 '*' +#10 OBJECTID self +#10 '*' +#10 OBJECTID c +#10 '+' +#10 '+' +*) diff --git a/tests/lexer/iis5_error.txt b/tests/lexer/iis5_error.txt new file mode 100644 index 00000000..b3dbadcb --- /dev/null +++ b/tests/lexer/iis5_error.txt @@ -0,0 +1,2 @@ +(8, 62) - LexicographicError: ERROR "[" +(8, 89) - LexicographicError: ERROR "]" diff --git a/tests/lexer/iis6.cl b/tests/lexer/iis6.cl new file mode 100644 index 00000000..1042f132 --- /dev/null +++ b/tests/lexer/iis6.cl @@ -0,0 +1,125 @@ +(* Integers, Identifiers, and Special Notation *) + +factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 resto p = 1: {@.@ for x in range(len(b))} + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) + + +class Class if then else fi testing Testing ~007agent_bond _james_007bones___ + + + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +loop pool while tRuE or noT faLsE let in case of ESAC + +(* +#3 OBJECTID factorial +#3 '(' +#3 INT_CONST 5 +#3 ')' +#3 '=' +#3 INT_CONST 120 +#3 ',' +#3 INT_CONST 2 +#3 '+' +#3 INT_CONST 2 +#3 '=' +#3 INT_CONST 5 +#3 OBJECTID or +#3 TYPEID E +#3 '=' +#3 OBJECTID mc2 +#3 ';' +#3 OBJECTID p +#3 '+' +#3 INT_CONST 1 +#3 OBJECTID resto +#3 OBJECTID p +#3 '=' +#3 INT_CONST 1 +#3 ':' +#3 '{' +#3 '@' +#3 '.' +#3 '@' +#3 OBJECTID for +#3 OBJECTID x +#3 IN +#3 OBJECTID range +#3 '(' +#3 OBJECTID len +#3 '(' +#3 OBJECTID b +#3 ')' +#3 ')' +#3 '}' +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#8 CLASS +#8 CLASS +#8 IF +#8 THEN +#8 ELSE +#8 FI +#8 OBJECTID testing +#8 TYPEID Testing +#8 '~' +#8 INT_CONST 007 +#8 OBJECTID agent_bond +#8 ERROR "_" +#8 OBJECTID james_007bones___ +#12 INT_CONST 0007 +#12 INT_CONST 123 +#12 '+' +#12 INT_CONST 1 +#12 '-' +#12 INT_CONST 1 +#12 '+' +#12 INT_CONST 90 +#12 '-' +#12 INT_CONST 09 +#12 '+' +#12 INT_CONST 11113 +#12 '-' +#12 INT_CONST 4 +#12 OBJECTID r +#12 '*' +#12 OBJECTID a +#12 '*' +#12 OBJECTID self +#12 '*' +#12 OBJECTID c +#12 '+' +#12 '+' +#13 LOOP +#13 POOL +#13 WHILE +#13 BOOL_CONST true +#13 OBJECTID or +#13 NOT +#13 BOOL_CONST false +#13 LET +#13 IN +#13 CASE +#13 OF +#13 ESAC +*) \ No newline at end of file diff --git a/tests/lexer/iis6_error.txt b/tests/lexer/iis6_error.txt new file mode 100644 index 00000000..d7fad9c7 --- /dev/null +++ b/tests/lexer/iis6_error.txt @@ -0,0 +1 @@ +(8, 60) - LexicographicError: ERROR "_" diff --git a/tests/lexer/mixed1.cl b/tests/lexer/mixed1.cl new file mode 100644 index 00000000..803d58ef --- /dev/null +++ b/tests/lexer/mixed1.cl @@ -0,0 +1,14 @@ +"lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 +adsfasklj# +LKldsajf iNhERITS +"lkdsajf" + +(* +#1 STR_CONST "lkjdsafkljdsalfju0000dsafdsafu0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl" +#1 INT_CONST 123 +#2 OBJECTID adsfasklj +#2 ERROR "#" +#3 TYPEID LKldsajf +#3 INHERITS +#4 STR_CONST "lkdsajf" +*) \ No newline at end of file diff --git a/tests/lexer/test5_error.txt b/tests/lexer/mixed1_error.txt similarity index 100% rename from tests/lexer/test5_error.txt rename to tests/lexer/mixed1_error.txt diff --git a/tests/lexer/mixed2.cl b/tests/lexer/mixed2.cl new file mode 100644 index 00000000..12039e12 --- /dev/null +++ b/tests/lexer/mixed2.cl @@ -0,0 +1,20 @@ +"kjas\"lnnsdj\nfljrdsaf" +@.$.@ +@*%*@ +"alkjfldajf""dasfadsf + +(* +#1 STR_CONST "kjas\"lnnsdj\nfljrdsaf" +#2 '@' +#2 '.' +#2 ERROR "$" +#2 '.' +#2 '@' +#3 '@' +#3 '*' +#3 ERROR "%" +#3 '*' +#3 '@' +#4 STR_CONST "alkjfldajf" +#4 ERROR "Unterminated string constant" +*) \ No newline at end of file diff --git a/tests/lexer/mixed2_error.txt b/tests/lexer/mixed2_error.txt new file mode 100644 index 00000000..097dc2a0 --- /dev/null +++ b/tests/lexer/mixed2_error.txt @@ -0,0 +1,3 @@ +(2, 3) - LexicographicError: ERROR "$" +(3, 3) - LexicographicError: ERROR "%" +(4, 22) - LexicographicError: Unterminated string constant diff --git a/tests/lexer/string1.cl b/tests/lexer/string1.cl new file mode 100644 index 00000000..6c3c0083 --- /dev/null +++ b/tests/lexer/string1.cl @@ -0,0 +1,6 @@ +(* A non-escaped newline character may not appear in a string *) + +"This \ +is OK" +"This is not +OK" \ No newline at end of file diff --git a/tests/lexer/string1_error.txt b/tests/lexer/string1_error.txt new file mode 100644 index 00000000..078c12bb --- /dev/null +++ b/tests/lexer/string1_error.txt @@ -0,0 +1,2 @@ +(5, 13) - LexicographicError: Unterminated string constant +(6, 4) - LexicographicError: EOF in string constant \ No newline at end of file diff --git a/tests/lexer/string2.cl b/tests/lexer/string2.cl new file mode 100644 index 00000000..3704b6ae --- /dev/null +++ b/tests/lexer/string2.cl @@ -0,0 +1,19 @@ +(* A string may not contain EOF *) + +" May the Triforce \ + 0 \ + 0v0 \ + 0vvv0 \ + 0vvvvv0 \ + 0vvvvvvv0 \ + 0vvvvvvvvv0 \ + 0vvvvvvvvvvv0 \ + 000000000000000 \ + 0v0 0v0 \ + 0vvv0 0vvv0 \ + 0vvvvv0 0vvvvv0 \ + 0vvvvvvv0 0vvvvvvv0 \ + 0vvvvvvvvv0 0vvvvvvvvv0 \ + 0vvvvvvvvvvv0 0vvvvvvvvvvv0 \ + 00000000000000000000000000000 \ + be with you! \ No newline at end of file diff --git a/tests/lexer/string2_error.txt b/tests/lexer/string2_error.txt new file mode 100644 index 00000000..7fbbcb52 --- /dev/null +++ b/tests/lexer/string2_error.txt @@ -0,0 +1 @@ +(19, 29) - LexicographicError: EOF in string constant \ No newline at end of file diff --git a/tests/lexer/string3.cl b/tests/lexer/string3.cl new file mode 100644 index 00000000..78abc497 Binary files /dev/null and b/tests/lexer/string3.cl differ diff --git a/tests/lexer/string3_error.txt b/tests/lexer/string3_error.txt new file mode 100644 index 00000000..35695d07 --- /dev/null +++ b/tests/lexer/string3_error.txt @@ -0,0 +1 @@ +(8, 4) - LexicographicError: String contains null character \ No newline at end of file diff --git a/tests/lexer/string4.cl b/tests/lexer/string4.cl new file mode 100644 index 00000000..f4d39c02 --- /dev/null +++ b/tests/lexer/string4.cl @@ -0,0 +1,38 @@ +class Main { + str <- "The big brown fox + jumped over the fence"; + main() : Object { + { + out_string("Yay! This is the newest shites ); + } + }; +}; + +(* +#1 CLASS +#1 TYPEID Main +#1 '{' +#2 OBJECTID str +#2 ASSIGN +#3 ERROR "Unterminated string constant" +#3 OBJECTID jumped +#3 OBJECTID over +#3 OBJECTID the +#3 OBJECTID fence +#4 ERROR "Unterminated string constant" +#4 OBJECTID main +#4 '(' +#4 ')' +#4 ':' +#4 TYPEID Object +#4 '{' +#5 '{' +#6 OBJECTID out_string +#6 '(' +#7 ERROR "Unterminated string constant" +#7 '}' +#8 '}' +#8 ';' +#9 '}' +#9 ';' +*) \ No newline at end of file diff --git a/tests/lexer/string4_error.txt b/tests/lexer/string4_error.txt new file mode 100644 index 00000000..5ab0ea84 --- /dev/null +++ b/tests/lexer/string4_error.txt @@ -0,0 +1,3 @@ +(2, 30) - LexicographicError: Unterminated string constant +(3, 36) - LexicographicError: Unterminated string constant +(6, 58) - LexicographicError: Unterminated string constant \ No newline at end of file diff --git a/tests/lexer/test1.cl b/tests/lexer/test1.cl deleted file mode 100644 index 43ea44f6..00000000 --- a/tests/lexer/test1.cl +++ /dev/null @@ -1,9 +0,0 @@ -class Main { - str <- "The big brown fox - jumped over the fence"; - main() : Object { - { - out_string("Yay! This is the newest shites ); - } - }; -}; diff --git a/tests/lexer/test1_error.txt b/tests/lexer/test1_error.txt deleted file mode 100644 index 5145209d..00000000 --- a/tests/lexer/test1_error.txt +++ /dev/null @@ -1,3 +0,0 @@ -(3, 4) - LexicographicError: Unterminated string constant -(4, 2) - LexicographicError: Unterminated string constant -(7, 4) - LexicographicError: Unterminated string constant \ No newline at end of file diff --git a/tests/lexer/test3.cl b/tests/lexer/test3.cl deleted file mode 100644 index 1fb6cedb..00000000 --- a/tests/lexer/test3.cl +++ /dev/null @@ -1,46 +0,0 @@ -class Error() { - - (* There was once a comment, - that was quite long. - But, the reader soon discovered that - the comment was indeed longer than - previously assumed. Now, the reader - was in a real dilemma; is the comment - ever gonna end? If I stop reading, will - it end? - He started imagining all sorts of things. - He thought about heisenberg's cat and how - how that relates to the end of the sentence. - He thought to himself "I'm gonna stop reading". - "If I keep reading this comment, I'm gonna know - the fate of this sentence; That will be disastorous." - He knew that such a comment was gonna extend to - another file. It was too awesome to be contained in - a single file. And he would have kept reading too... - if only... - cool wasn't a super-duper-fab-awesomest language; - but cool is that language; - "This comment shall go not cross this file" said cool. - Alas! The reader could read no more. - There was once a comment, - that was quite long. - But, the reader soon discovered that - the comment was indeed longer than - previously assumed. Now, the reader - was in a real dilemma; is the comment - ever gonna end? If I stop reading, will - it end? - He started imagining all sorts of things. - He thought about heisenberg's cat and how - how that relates to the end of the sentence. - He thought to himself "I'm gonna stop reading". - "If I keep reading this comment, I'm gonna know - the fate of this sentence; That will be disastorous." - He knew that such a comment was gonna extend to - another file. It was too awesome to be contained in - a single file. And he would have kept reading too... - if only... - cool wasn't a super-duper-fab-awesomest language; - but cool is that language; - "This comment shall go not cross this file" said cool. - Alas! The reader could read no more. \ No newline at end of file diff --git a/tests/lexer/test3_error.txt b/tests/lexer/test3_error.txt deleted file mode 100644 index dc48da75..00000000 --- a/tests/lexer/test3_error.txt +++ /dev/null @@ -1 +0,0 @@ -(46, 40) - LexicographicError: EOF in comment diff --git a/tests/lexer/test5.cl b/tests/lexer/test5.cl deleted file mode 100644 index 879e27a6..00000000 --- a/tests/lexer/test5.cl +++ /dev/null @@ -1,4 +0,0 @@ -"lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 -adsfasklj# -LKldsajf -"lkdsajf" \ No newline at end of file diff --git a/tests/lexer/test6.cl b/tests/lexer/test6.cl deleted file mode 100644 index d420df7c..00000000 --- a/tests/lexer/test6.cl +++ /dev/null @@ -1,6 +0,0 @@ -"kjas\"lnnsdj\nfljrdsaf" -$ -$ -% -% -"alkjfldajf""dasfadsf \ No newline at end of file diff --git a/tests/lexer/test6_error.txt b/tests/lexer/test6_error.txt deleted file mode 100644 index 4ca5899e..00000000 --- a/tests/lexer/test6_error.txt +++ /dev/null @@ -1,5 +0,0 @@ -(2, 1) - LexicographicError: ERROR "$" -(3, 1) - LexicographicError: ERROR "$" -(4, 1) - LexicographicError: ERROR "%" -(5, 1) - LexicographicError: ERROR "%" -(6, 22) - LexicographicError: EOF in string constant diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 28f7fc28..2a27223d 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -3,11 +3,11 @@ from utils import compare_errors tests_dir = __file__.rpartition('/')[0] + '/lexer/' -tests = [(tests_dir + file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -@pytest.mark.run(order=1) @pytest.mark.lexer @pytest.mark.error +@pytest.mark.run(order=1) @pytest.mark.parametrize("cool_file", tests) def test_lexer_errors(compiler_path, cool_file): - compare_errors(compiler_path, cool_file, cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file diff --git a/tests/parser/assignment1.cl b/tests/parser/assignment1.cl new file mode 100644 index 00000000..75b4c5bb --- /dev/null +++ b/tests/parser/assignment1.cl @@ -0,0 +1,37 @@ +(* An assignment has the form <- *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(): String { + Test1 <- "Hello World" -- Identifiers begin with a lower case letter + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/assignment1_error.txt b/tests/parser/assignment1_error.txt new file mode 100644 index 00000000..cef0d394 --- /dev/null +++ b/tests/parser/assignment1_error.txt @@ -0,0 +1 @@ +(29, 9) - SyntacticError: ERROR at or near "Test1" \ No newline at end of file diff --git a/tests/parser/assignment2.cl b/tests/parser/assignment2.cl new file mode 100644 index 00000000..4efb9648 --- /dev/null +++ b/tests/parser/assignment2.cl @@ -0,0 +1,37 @@ +(* An assignment has the form <- *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 - 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(): Int { + test1 <-- ~(1 + 2 + 3 + 4 + 5) -- The left side must be an expression + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/assignment2_error.txt b/tests/parser/assignment2_error.txt new file mode 100644 index 00000000..dc611c15 --- /dev/null +++ b/tests/parser/assignment2_error.txt @@ -0,0 +1 @@ +(29, 17) - SyntacticError: ERROR at or near "-" \ No newline at end of file diff --git a/tests/parser/assignment3.cl b/tests/parser/assignment3.cl new file mode 100644 index 00000000..ff633f33 --- /dev/null +++ b/tests/parser/assignment3.cl @@ -0,0 +1,37 @@ +(* An assignment has the form <- *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(): Bool { + test1 <- true++ -- The left side must be an expression + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/assignment3_error.txt b/tests/parser/assignment3_error.txt new file mode 100644 index 00000000..a69ac3a8 --- /dev/null +++ b/tests/parser/assignment3_error.txt @@ -0,0 +1 @@ +(29, 23) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/attribute1.cl b/tests/parser/attribute1.cl new file mode 100644 index 00000000..063a02c0 --- /dev/null +++ b/tests/parser/attribute1.cl @@ -0,0 +1,34 @@ +(* An attribute of class A specifies a variable that is part of the state of objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + -- Attributes names must begin with lowercase letters + Test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/attribute1_error.txt b/tests/parser/attribute1_error.txt new file mode 100644 index 00000000..a4e9eb06 --- /dev/null +++ b/tests/parser/attribute1_error.txt @@ -0,0 +1 @@ +(17, 5) - SyntacticError: ERROR at or near "Test2" \ No newline at end of file diff --git a/tests/parser/attribute2.cl b/tests/parser/attribute2.cl new file mode 100644 index 00000000..c0521148 --- /dev/null +++ b/tests/parser/attribute2.cl @@ -0,0 +1,34 @@ +(* An attribute of class A specifies a variable that is part of the state of objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + -- Type names must begin with uppercase letters + test3: string <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/attribute2_error.txt b/tests/parser/attribute2_error.txt new file mode 100644 index 00000000..b02a52ee --- /dev/null +++ b/tests/parser/attribute2_error.txt @@ -0,0 +1 @@ +(19, 12) - SyntacticError: ERROR at or near "string" \ No newline at end of file diff --git a/tests/parser/attribute3.cl b/tests/parser/attribute3.cl new file mode 100644 index 00000000..d858ae47 --- /dev/null +++ b/tests/parser/attribute3.cl @@ -0,0 +1,34 @@ +(* An attribute of class A specifies a variable that is part of the state of objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + -- Expected '<-' not '<=' + test3: String <= "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/attribute3_error.txt b/tests/parser/attribute3_error.txt new file mode 100644 index 00000000..71f5bc0b --- /dev/null +++ b/tests/parser/attribute3_error.txt @@ -0,0 +1 @@ +(19, 19) - SyntacticError: ERROR at or near "<=" \ No newline at end of file diff --git a/tests/parser/block1.cl b/tests/parser/block1.cl new file mode 100644 index 00000000..3613d926 --- /dev/null +++ b/tests/parser/block1.cl @@ -0,0 +1,87 @@ +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2 -- Missing ";" + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/block1_error.txt b/tests/parser/block1_error.txt new file mode 100644 index 00000000..c78fb0b9 --- /dev/null +++ b/tests/parser/block1_error.txt @@ -0,0 +1 @@ +(56, 17) - SyntacticError: ERROR at or near "}" \ No newline at end of file diff --git a/tests/parser/block2.cl b/tests/parser/block2.cl new file mode 100644 index 00000000..f485dd0b --- /dev/null +++ b/tests/parser/block2.cl @@ -0,0 +1,87 @@ +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + -- Missing "{" + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/block2_error.txt b/tests/parser/block2_error.txt new file mode 100644 index 00000000..f85f4303 --- /dev/null +++ b/tests/parser/block2_error.txt @@ -0,0 +1 @@ +(49, 23) - SyntacticError: ERROR at or near ";" \ No newline at end of file diff --git a/tests/parser/block3.cl b/tests/parser/block3.cl new file mode 100644 index 00000000..ae1598c3 --- /dev/null +++ b/tests/parser/block3.cl @@ -0,0 +1,87 @@ +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + -- Missing "}" + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/block3_error.txt b/tests/parser/block3_error.txt new file mode 100644 index 00000000..cda9949a --- /dev/null +++ b/tests/parser/block3_error.txt @@ -0,0 +1 @@ +(57, 13) - SyntacticError: ERROR at or near "pool" \ No newline at end of file diff --git a/tests/parser/block4.cl b/tests/parser/block4.cl new file mode 100644 index 00000000..8fd883d0 --- /dev/null +++ b/tests/parser/block4.cl @@ -0,0 +1,88 @@ +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + true++; -- Only expressions + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/block4_error.txt b/tests/parser/block4_error.txt new file mode 100644 index 00000000..ddbeb32e --- /dev/null +++ b/tests/parser/block4_error.txt @@ -0,0 +1 @@ +(56, 26) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/case1.cl b/tests/parser/case1.cl new file mode 100644 index 00000000..c2f50880 --- /dev/null +++ b/tests/parser/case1.cl @@ -0,0 +1,91 @@ +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + -- Every case expression must have at least one branch + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/case1_error.txt b/tests/parser/case1_error.txt new file mode 100644 index 00000000..61fca14f --- /dev/null +++ b/tests/parser/case1_error.txt @@ -0,0 +1 @@ +(63, 9) - SyntacticError: ERROR at or near ESAC \ No newline at end of file diff --git a/tests/parser/case2.cl b/tests/parser/case2.cl new file mode 100644 index 00000000..f9162e49 --- /dev/null +++ b/tests/parser/case2.cl @@ -0,0 +1,93 @@ +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case "2 + 2" of + x: Int => new IO.out_string("Es un entero!") -- Missing ";" + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/case2_error.txt b/tests/parser/case2_error.txt new file mode 100644 index 00000000..40b030dd --- /dev/null +++ b/tests/parser/case2_error.txt @@ -0,0 +1 @@ +(63, 13) - SyntacticError: ERROR at or near "y" \ No newline at end of file diff --git a/tests/parser/case3.cl b/tests/parser/case3.cl new file mode 100644 index 00000000..a7eedc18 --- /dev/null +++ b/tests/parser/case3.cl @@ -0,0 +1,93 @@ +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + false of + x: Int => new IO.out_string("Es un entero!"); + y: string => new IO.out_string("Es una cadena!"); -- Type identifiers starts with a uppercase letter + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/case3_error.txt b/tests/parser/case3_error.txt new file mode 100644 index 00000000..f25c5c56 --- /dev/null +++ b/tests/parser/case3_error.txt @@ -0,0 +1 @@ +(63, 16) - SyntacticError: ERROR at or near "string" \ No newline at end of file diff --git a/tests/parser/case4.cl b/tests/parser/case4.cl new file mode 100644 index 00000000..25ca3858 --- /dev/null +++ b/tests/parser/case4.cl @@ -0,0 +1,93 @@ +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case true of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + Mazinger_Z: Bool => new IO.out_string("Es un booleano!"); -- Identifiers starts with a lowercase letter + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/case4_error.txt b/tests/parser/case4_error.txt new file mode 100644 index 00000000..c5a16dde --- /dev/null +++ b/tests/parser/case4_error.txt @@ -0,0 +1 @@ +(64, 13) - SyntacticError: ERROR at or near "Mazinger_Z" \ No newline at end of file diff --git a/tests/parser/case5.cl b/tests/parser/case5.cl new file mode 100644 index 00000000..b36c663e --- /dev/null +++ b/tests/parser/case5.cl @@ -0,0 +1,93 @@ +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case test2 of + x: Int <- new IO.out_string("Es un entero!"); -- Must be '=>' not '<-'; + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/case5_error.txt b/tests/parser/case5_error.txt new file mode 100644 index 00000000..fc6ec0ed --- /dev/null +++ b/tests/parser/case5_error.txt @@ -0,0 +1 @@ +(62, 20) - SyntacticError: ERROR at or near ASSIGN \ No newline at end of file diff --git a/tests/parser/case6.cl b/tests/parser/case6.cl new file mode 100644 index 00000000..66e7df2a --- /dev/null +++ b/tests/parser/case6.cl @@ -0,0 +1,93 @@ +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 -- Missing "of" + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/case6_error.txt b/tests/parser/case6_error.txt new file mode 100644 index 00000000..2ae2f723 --- /dev/null +++ b/tests/parser/case6_error.txt @@ -0,0 +1 @@ +(62, 13) - SyntacticError: ERROR at or near "x" \ No newline at end of file diff --git a/tests/parser/class1.cl b/tests/parser/class1.cl new file mode 100644 index 00000000..f4815e3f --- /dev/null +++ b/tests/parser/class1.cl @@ -0,0 +1,20 @@ +(* A class is a list of features *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + testing(): Int { + 2 + 2 + }; +}; + +-- Class names must begin with uppercase letters +class alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class1_error.txt b/tests/parser/class1_error.txt new file mode 100644 index 00000000..acaa52a6 --- /dev/null +++ b/tests/parser/class1_error.txt @@ -0,0 +1 @@ +(16, 7) - SyntacticError: ERROR at or near "alpha" \ No newline at end of file diff --git a/tests/parser/class2.cl b/tests/parser/class2.cl new file mode 100644 index 00000000..f363b032 --- /dev/null +++ b/tests/parser/class2.cl @@ -0,0 +1,20 @@ +(* A class is a list of features *) + +CLaSS Main { + main(): Object { + (new Alpha).print() + }; +}; + +CLaSS Test { + testing(): Int { + 2 + 2 + }; +}; + +-- Type names must begin with uppercase letters +CLaSS Alpha iNHeRiTS iO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class2_error.txt b/tests/parser/class2_error.txt new file mode 100644 index 00000000..59d06591 --- /dev/null +++ b/tests/parser/class2_error.txt @@ -0,0 +1 @@ +(16, 22) - SyntacticError: ERROR at or near "iO" \ No newline at end of file diff --git a/tests/parser/class3.cl b/tests/parser/class3.cl new file mode 100644 index 00000000..0c801372 --- /dev/null +++ b/tests/parser/class3.cl @@ -0,0 +1,34 @@ +(* A class is a list of features *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Missing semicolon + testing2(a: Alpha, b: Int): Int { + 2 + 2 + } + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class3_error.txt b/tests/parser/class3_error.txt new file mode 100644 index 00000000..bc2f946b --- /dev/null +++ b/tests/parser/class3_error.txt @@ -0,0 +1 @@ +(25, 5) - SyntacticError: ERROR at or near "testing3" \ No newline at end of file diff --git a/tests/parser/class4.cl b/tests/parser/class4.cl new file mode 100644 index 00000000..5c286b5e --- /dev/null +++ b/tests/parser/class4.cl @@ -0,0 +1,36 @@ +(* A class is a list of features *) + +CLaSS Main { + main(): Object { + (new Alpha).print() + }; +}; + +CLaSS Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + -- Only features + 2 + 2; + + testing3(): String { + "2 + 2" + }; +}; + +CLaSS Alpha iNHeRiTS IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class4_error.txt b/tests/parser/class4_error.txt new file mode 100644 index 00000000..1007f033 --- /dev/null +++ b/tests/parser/class4_error.txt @@ -0,0 +1 @@ +(25, 5) - SyntacticError: ERROR at or near "2" \ No newline at end of file diff --git a/tests/parser/class5.cl b/tests/parser/class5.cl new file mode 100644 index 00000000..3f40c36e --- /dev/null +++ b/tests/parser/class5.cl @@ -0,0 +1,34 @@ +(* A class is a list of features *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +-- Missing '{' +class Test + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class5_error.txt b/tests/parser/class5_error.txt new file mode 100644 index 00000000..400e4d61 --- /dev/null +++ b/tests/parser/class5_error.txt @@ -0,0 +1 @@ +(11, 5) - SyntacticError: ERROR at or near "test1" \ No newline at end of file diff --git a/tests/parser/class6.cl b/tests/parser/class6.cl new file mode 100644 index 00000000..8501d259 --- /dev/null +++ b/tests/parser/class6.cl @@ -0,0 +1,34 @@ +(* A class is a list of features *) + +CLaSS Main { + main(): Object { + (new Alpha).print() + }; +}; + +-- Missing '}' +CLaSS Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +; + +CLaSS Alpha iNHeRiTS IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class6_error.txt b/tests/parser/class6_error.txt new file mode 100644 index 00000000..73574c94 --- /dev/null +++ b/tests/parser/class6_error.txt @@ -0,0 +1 @@ +(28, 1) - SyntacticError: ERROR at or near ";" \ No newline at end of file diff --git a/tests/parser/conditional1.cl b/tests/parser/conditional1.cl new file mode 100644 index 00000000..4d546fc4 --- /dev/null +++ b/tests/parser/conditional1.cl @@ -0,0 +1,69 @@ +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + if a.length() < b.length() -- Mising "then" + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + else + if a.length() = b.length() then + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + else + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fi + fi + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/conditional1_error.txt b/tests/parser/conditional1_error.txt new file mode 100644 index 00000000..ee533fd8 --- /dev/null +++ b/tests/parser/conditional1_error.txt @@ -0,0 +1 @@ +(34, 13) - SyntacticError: ERROR at or near NEW \ No newline at end of file diff --git a/tests/parser/conditional2.cl b/tests/parser/conditional2.cl new file mode 100644 index 00000000..4f10c295 --- /dev/null +++ b/tests/parser/conditional2.cl @@ -0,0 +1,69 @@ +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + if a.length() < b.length() then + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + else + if a.length() = b.length() then + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + else + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + -- Missing "fi" + fi + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/conditional2_error.txt b/tests/parser/conditional2_error.txt new file mode 100644 index 00000000..c72f78d7 --- /dev/null +++ b/tests/parser/conditional2_error.txt @@ -0,0 +1 @@ +(42, 5) - SyntacticError: ERROR at or near "}" \ No newline at end of file diff --git a/tests/parser/conditional3.cl b/tests/parser/conditional3.cl new file mode 100644 index 00000000..67e991ad --- /dev/null +++ b/tests/parser/conditional3.cl @@ -0,0 +1,69 @@ +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + iF a.length() < b.length() tHen + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + elsE + if a.length() = b.length() then + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + eLseif -- elseif isn't a keyword + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/conditional3_error.txt b/tests/parser/conditional3_error.txt new file mode 100644 index 00000000..ad95552b --- /dev/null +++ b/tests/parser/conditional3_error.txt @@ -0,0 +1 @@ +(38, 13) - SyntacticError: ERROR at or near "eLseif" \ No newline at end of file diff --git a/tests/parser/conditional4.cl b/tests/parser/conditional4.cl new file mode 100644 index 00000000..0792fdc8 --- /dev/null +++ b/tests/parser/conditional4.cl @@ -0,0 +1,73 @@ +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(): Int { + if true++ then 1 else 0 -- Condition must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/conditional4_error.txt b/tests/parser/conditional4_error.txt new file mode 100644 index 00000000..f5511445 --- /dev/null +++ b/tests/parser/conditional4_error.txt @@ -0,0 +1 @@ +(45, 17) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/conditional5.cl b/tests/parser/conditional5.cl new file mode 100644 index 00000000..0c1e1aad --- /dev/null +++ b/tests/parser/conditional5.cl @@ -0,0 +1,73 @@ +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(): Int { + if true then true++ else 0 -- If branch must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/conditional5_error.txt b/tests/parser/conditional5_error.txt new file mode 100644 index 00000000..b3214010 --- /dev/null +++ b/tests/parser/conditional5_error.txt @@ -0,0 +1 @@ +(45, 27) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/conditional6.cl b/tests/parser/conditional6.cl new file mode 100644 index 00000000..02310404 --- /dev/null +++ b/tests/parser/conditional6.cl @@ -0,0 +1,73 @@ +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(): Int { + if true then 1 else false++ -- Else branch must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/conditional6_error.txt b/tests/parser/conditional6_error.txt new file mode 100644 index 00000000..968b78ad --- /dev/null +++ b/tests/parser/conditional6_error.txt @@ -0,0 +1 @@ +(45, 35) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/dispatch1.cl b/tests/parser/dispatch1.cl new file mode 100644 index 00000000..2ca39471 --- /dev/null +++ b/tests/parser/dispatch1.cl @@ -0,0 +1,45 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + Test1.testing4(1, 2).testing4(3, 4).testing4(5, 6) -- Objet identifiers begin with a lower case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch1_error.txt b/tests/parser/dispatch1_error.txt new file mode 100644 index 00000000..ba8e9e84 --- /dev/null +++ b/tests/parser/dispatch1_error.txt @@ -0,0 +1 @@ +(37, 9) - SyntacticError: ERROR at or near "Test1" \ No newline at end of file diff --git a/tests/parser/dispatch2.cl b/tests/parser/dispatch2.cl new file mode 100644 index 00000000..0b57467a --- /dev/null +++ b/tests/parser/dispatch2.cl @@ -0,0 +1,45 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13,) -- Extra comma + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch2_error.txt b/tests/parser/dispatch2_error.txt new file mode 100644 index 00000000..134e266b --- /dev/null +++ b/tests/parser/dispatch2_error.txt @@ -0,0 +1 @@ +(37, 84) - SyntacticError: ERROR at or near ")" \ No newline at end of file diff --git a/tests/parser/dispatch3.cl b/tests/parser/dispatch3.cl new file mode 100644 index 00000000..9f1a5aff --- /dev/null +++ b/tests/parser/dispatch3.cl @@ -0,0 +1,45 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).Testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) -- Identifiers begin with a lower case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch3_error.txt b/tests/parser/dispatch3_error.txt new file mode 100644 index 00000000..86d2d514 --- /dev/null +++ b/tests/parser/dispatch3_error.txt @@ -0,0 +1 @@ +(37, 38) - SyntacticError: ERROR at or near "Testing4" \ No newline at end of file diff --git a/tests/parser/dispatch4.cl b/tests/parser/dispatch4.cl new file mode 100644 index 00000000..d1efc469 --- /dev/null +++ b/tests/parser/dispatch4.cl @@ -0,0 +1,53 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + self.testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true++) -- Arguments must be expressions + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch4_error.txt b/tests/parser/dispatch4_error.txt new file mode 100644 index 00000000..d03bb4c5 --- /dev/null +++ b/tests/parser/dispatch4_error.txt @@ -0,0 +1 @@ +(45, 81) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/dispatch5.cl b/tests/parser/dispatch5.cl new file mode 100644 index 00000000..63a5afa7 --- /dev/null +++ b/tests/parser/dispatch5.cl @@ -0,0 +1,53 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, ,true + fALSE) -- Extra comma + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch5_error.txt b/tests/parser/dispatch5_error.txt new file mode 100644 index 00000000..3fc39c62 --- /dev/null +++ b/tests/parser/dispatch5_error.txt @@ -0,0 +1 @@ +(45, 71) - SyntacticError: ERROR at or near "," \ No newline at end of file diff --git a/tests/parser/dispatch6.cl b/tests/parser/dispatch6.cl new file mode 100644 index 00000000..0a953e2e --- /dev/null +++ b/tests/parser/dispatch6.cl @@ -0,0 +1,57 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@object.copy() -- Type identifiers begin with a upper case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch6_error.txt b/tests/parser/dispatch6_error.txt new file mode 100644 index 00000000..543f3a38 --- /dev/null +++ b/tests/parser/dispatch6_error.txt @@ -0,0 +1 @@ +(49, 15) - SyntacticError: ERROR at or near "object" \ No newline at end of file diff --git a/tests/parser/dispatch7.cl b/tests/parser/dispatch7.cl new file mode 100644 index 00000000..3ecac4d0 --- /dev/null +++ b/tests/parser/dispatch7.cl @@ -0,0 +1,57 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.Copy() -- Identifiers begin with a lower case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch7_error.txt b/tests/parser/dispatch7_error.txt new file mode 100644 index 00000000..27235d11 --- /dev/null +++ b/tests/parser/dispatch7_error.txt @@ -0,0 +1 @@ +(49, 22) - SyntacticError: ERROR at or near "Copy" \ No newline at end of file diff --git a/tests/parser/dispatch8.cl b/tests/parser/dispatch8.cl new file mode 100644 index 00000000..eef0455e --- /dev/null +++ b/tests/parser/dispatch8.cl @@ -0,0 +1,57 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy(,) -- Extra comma + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch8_error.txt b/tests/parser/dispatch8_error.txt new file mode 100644 index 00000000..04704520 --- /dev/null +++ b/tests/parser/dispatch8_error.txt @@ -0,0 +1 @@ +(49, 27) - SyntacticError: ERROR at or near "," \ No newline at end of file diff --git a/tests/parser/dispatch9.cl b/tests/parser/dispatch9.cl new file mode 100644 index 00000000..5fdef22d --- /dev/null +++ b/tests/parser/dispatch9.cl @@ -0,0 +1,61 @@ +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; + + testing5(): Object { + test1:Object.copy() -- Must be '@' not ':' + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/dispatch9_error.txt b/tests/parser/dispatch9_error.txt new file mode 100644 index 00000000..eb0b3397 --- /dev/null +++ b/tests/parser/dispatch9_error.txt @@ -0,0 +1 @@ +(53, 14) - SyntacticError: ERROR at or near ":" \ No newline at end of file diff --git a/tests/parser/err2.cl b/tests/parser/err2.cl deleted file mode 100644 index 40149b89..00000000 --- a/tests/parser/err2.cl +++ /dev/null @@ -1,14 +0,0 @@ -class Main { - main(): Object { - (new alpha).print() - }; - -}; - -(* Class names must begin with uppercase letters *) -class alpha inherits IO { - print() : Object { - out_string("reached!!\n"); - }; -}; - diff --git a/tests/parser/err2_error.txt b/tests/parser/err2_error.txt deleted file mode 100644 index 92e47e37..00000000 --- a/tests/parser/err2_error.txt +++ /dev/null @@ -1,2 +0,0 @@ -(3, 10) - SyntacticError: ERROR at or near "alpha" -(9, 7) - SyntacticError: ERROR at or near "alpha" \ No newline at end of file diff --git a/tests/parser/isprime.cl b/tests/parser/isprime.cl deleted file mode 100644 index 5adaeda9..00000000 --- a/tests/parser/isprime.cl +++ /dev/null @@ -1,40 +0,0 @@ -class Main inherits IO { - main() : Object { - { - out_string("Enter a number to check if number is prime\n"); - let i : Int <- in_int() in { - if(i <= 1) then { - out_string("Invalid Input\n"); - abort(); - } else { - if (isPrime(i) = 1) then - out_string("Number is prime\n") - else - out_string("Number is composite\n") - fi; - } - fi; - }; - } - }; - - mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. - i - (i/k)*k - }; - - isPrime(i : Int) : Int { - { - let x : Int <- 2, - c : Int <- 1 in - { - while (not (x = i)) loop - if (mod(i, x) = 0) then { - c <- 0; - x <- i; - } else x <- x + 1 fi - pool; - c; - }; - } - }; -}; diff --git a/tests/parser/isprime_error.txt b/tests/parser/isprime_error.txt deleted file mode 100644 index ea89e135..00000000 --- a/tests/parser/isprime_error.txt +++ /dev/null @@ -1 +0,0 @@ -(21, 15) - SyntacticError: Error at or near ')' diff --git a/tests/parser/let1.cl b/tests/parser/let1.cl new file mode 100644 index 00000000..576ae383 --- /dev/null +++ b/tests/parser/let1.cl @@ -0,0 +1,85 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let Count: Int <- 0, pow: Int <- 1 -- Object identifiers starts with a lowercase letter + in { + -- count <- 0; + -- pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let1_error.txt b/tests/parser/let1_error.txt new file mode 100644 index 00000000..8b7fe63d --- /dev/null +++ b/tests/parser/let1_error.txt @@ -0,0 +1 @@ +(45, 13) - SyntacticError: ERROR at or near "Count" \ No newline at end of file diff --git a/tests/parser/let2.cl b/tests/parser/let2.cl new file mode 100644 index 00000000..4cfaef0f --- /dev/null +++ b/tests/parser/let2.cl @@ -0,0 +1,85 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int, pow: int <- 1 -- Type identifiers starts with a uppercase letter + in { + count <- 0; + -- pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let2_error.txt b/tests/parser/let2_error.txt new file mode 100644 index 00000000..6fb3f8e9 --- /dev/null +++ b/tests/parser/let2_error.txt @@ -0,0 +1 @@ +(45, 30) - SyntacticError: ERROR at or near "int" \ No newline at end of file diff --git a/tests/parser/let3.cl b/tests/parser/let3.cl new file mode 100644 index 00000000..91e567fd --- /dev/null +++ b/tests/parser/let3.cl @@ -0,0 +1,85 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int, pow: Int, -- Extra comma + in { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let3_error.txt b/tests/parser/let3_error.txt new file mode 100644 index 00000000..71fa0881 --- /dev/null +++ b/tests/parser/let3_error.txt @@ -0,0 +1 @@ +(46, 9) - SyntacticError: ERROR at or near IN \ No newline at end of file diff --git a/tests/parser/let4.cl b/tests/parser/let4.cl new file mode 100644 index 00000000..a716c332 --- /dev/null +++ b/tests/parser/let4.cl @@ -0,0 +1,85 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- true++, pow: Int <- 1 -- Initialization must be an expression + in { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let4_error.txt b/tests/parser/let4_error.txt new file mode 100644 index 00000000..e12c7478 --- /dev/null +++ b/tests/parser/let4_error.txt @@ -0,0 +1 @@ +(45, 32) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/let5.cl b/tests/parser/let5.cl new file mode 100644 index 00000000..d974cc13 --- /dev/null +++ b/tests/parser/let5.cl @@ -0,0 +1,85 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int = 0, pow: Int -- Must be '<-' not '=' + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let5_error.txt b/tests/parser/let5_error.txt new file mode 100644 index 00000000..e561f846 --- /dev/null +++ b/tests/parser/let5_error.txt @@ -0,0 +1 @@ +(45, 24) - SyntacticError: ERROR at or near "=" \ No newline at end of file diff --git a/tests/parser/let6.cl b/tests/parser/let6.cl new file mode 100644 index 00000000..b6e51d7e --- /dev/null +++ b/tests/parser/let6.cl @@ -0,0 +1,74 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int <- 1 + in false++ -- Let body must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let6_error.txt b/tests/parser/let6_error.txt new file mode 100644 index 00000000..7a77928b --- /dev/null +++ b/tests/parser/let6_error.txt @@ -0,0 +1 @@ +(46, 18) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/let7.cl b/tests/parser/let7.cl new file mode 100644 index 00000000..6fd63e6a --- /dev/null +++ b/tests/parser/let7.cl @@ -0,0 +1,85 @@ +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + (* Missing "in" *) { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/let7_error.txt b/tests/parser/let7_error.txt new file mode 100644 index 00000000..654b1ce6 --- /dev/null +++ b/tests/parser/let7_error.txt @@ -0,0 +1 @@ +(46, 28) - SyntacticError: ERROR at or near "{" \ No newline at end of file diff --git a/tests/parser/loop1.cl b/tests/parser/loop1.cl new file mode 100644 index 00000000..7d0d7688 --- /dev/null +++ b/tests/parser/loop1.cl @@ -0,0 +1,78 @@ +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count < 1024*1024 + -- Missing "loop" + count <- count * 2 + pool + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/loop1_error.txt b/tests/parser/loop1_error.txt new file mode 100644 index 00000000..94248ff0 --- /dev/null +++ b/tests/parser/loop1_error.txt @@ -0,0 +1 @@ +(49, 13) - SyntacticError: ERROR at or near "count" \ No newline at end of file diff --git a/tests/parser/loop2.cl b/tests/parser/loop2.cl new file mode 100644 index 00000000..a9613c48 --- /dev/null +++ b/tests/parser/loop2.cl @@ -0,0 +1,78 @@ +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count < 1024*1024 + loop + count <- count * 2 + -- Missing "pool" + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/loop2_error.txt b/tests/parser/loop2_error.txt new file mode 100644 index 00000000..6447101f --- /dev/null +++ b/tests/parser/loop2_error.txt @@ -0,0 +1 @@ +(51, 5) - SyntacticError: ERROR at or near "}" \ No newline at end of file diff --git a/tests/parser/loop3.cl b/tests/parser/loop3.cl new file mode 100644 index 00000000..860adb4d --- /dev/null +++ b/tests/parser/loop3.cl @@ -0,0 +1,78 @@ +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count => 1024*1024 -- Condition must be an expression + loop + count <- count * 2 + pool + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/loop3_error.txt b/tests/parser/loop3_error.txt new file mode 100644 index 00000000..3da8bcde --- /dev/null +++ b/tests/parser/loop3_error.txt @@ -0,0 +1 @@ +(47, 21) - SyntacticError: ERROR at or near DARROW \ No newline at end of file diff --git a/tests/parser/loop4.cl b/tests/parser/loop4.cl new file mode 100644 index 00000000..0a1194e8 --- /dev/null +++ b/tests/parser/loop4.cl @@ -0,0 +1,78 @@ +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count < 1024*1024 + loop + count <- true++ -- While body must be an expression + pool + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/loop4_error.txt b/tests/parser/loop4_error.txt new file mode 100644 index 00000000..c39f35fe --- /dev/null +++ b/tests/parser/loop4_error.txt @@ -0,0 +1 @@ +(49, 27) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/method1.cl b/tests/parser/method1.cl new file mode 100644 index 00000000..fcfbbcd3 --- /dev/null +++ b/tests/parser/method1.cl @@ -0,0 +1,34 @@ +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Method names must begin with lowercase letters + Testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/method1_error.txt b/tests/parser/method1_error.txt new file mode 100644 index 00000000..0eff4199 --- /dev/null +++ b/tests/parser/method1_error.txt @@ -0,0 +1 @@ +(21, 5) - SyntacticError: ERROR at or near "Testing2" \ No newline at end of file diff --git a/tests/parser/method2.cl b/tests/parser/method2.cl new file mode 100644 index 00000000..d5bdfd85 --- /dev/null +++ b/tests/parser/method2.cl @@ -0,0 +1,34 @@ +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Parameter names must begin with lowercase letters + testing2(a: Alpha, B: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/method2_error.txt b/tests/parser/method2_error.txt new file mode 100644 index 00000000..1843fb7b --- /dev/null +++ b/tests/parser/method2_error.txt @@ -0,0 +1 @@ +(21, 24) - SyntacticError: ERROR at or near "B" \ No newline at end of file diff --git a/tests/parser/method3.cl b/tests/parser/method3.cl new file mode 100644 index 00000000..1e5c9eb5 --- /dev/null +++ b/tests/parser/method3.cl @@ -0,0 +1,34 @@ +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Type names must begin with uppercase letters + testing2(a: Alpha, b: int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/method3_error.txt b/tests/parser/method3_error.txt new file mode 100644 index 00000000..dbecf552 --- /dev/null +++ b/tests/parser/method3_error.txt @@ -0,0 +1 @@ +(21, 27) - SyntacticError: ERROR at or near "int" \ No newline at end of file diff --git a/tests/parser/method4.cl b/tests/parser/method4.cl new file mode 100644 index 00000000..019ada27 --- /dev/null +++ b/tests/parser/method4.cl @@ -0,0 +1,34 @@ +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + -- Missing paremeter + testing3(x: Int,): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/method4_error.txt b/tests/parser/method4_error.txt new file mode 100644 index 00000000..6421cee2 --- /dev/null +++ b/tests/parser/method4_error.txt @@ -0,0 +1 @@ +(25, 21) - SyntacticError: ERROR at or near ")" \ No newline at end of file diff --git a/tests/parser/method5.cl b/tests/parser/method5.cl new file mode 100644 index 00000000..13127f66 --- /dev/null +++ b/tests/parser/method5.cl @@ -0,0 +1,34 @@ +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + -- Type names must begin with uppercase letters + testing3(): string { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/method5_error.txt b/tests/parser/method5_error.txt new file mode 100644 index 00000000..9bda0704 --- /dev/null +++ b/tests/parser/method5_error.txt @@ -0,0 +1 @@ +(25, 17) - SyntacticError: ERROR at or near "string" \ No newline at end of file diff --git a/tests/parser/method6.cl b/tests/parser/method6.cl new file mode 100644 index 00000000..d48cd129 --- /dev/null +++ b/tests/parser/method6.cl @@ -0,0 +1,33 @@ +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Body can't be empty + testing2(a: Alpha, b: Int): Int { + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/method6_error.txt b/tests/parser/method6_error.txt new file mode 100644 index 00000000..e7d5de40 --- /dev/null +++ b/tests/parser/method6_error.txt @@ -0,0 +1 @@ +(22, 5) - SyntacticError: ERROR at or near "}" \ No newline at end of file diff --git a/tests/parser/mixed1.cl b/tests/parser/mixed1.cl new file mode 100644 index 00000000..a2787951 --- /dev/null +++ b/tests/parser/mixed1.cl @@ -0,0 +1,100 @@ +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}-- Mising ";" + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/mixed1_error.txt b/tests/parser/mixed1_error.txt new file mode 100644 index 00000000..d5b0ff8b --- /dev/null +++ b/tests/parser/mixed1_error.txt @@ -0,0 +1 @@ +(76, 1) - SyntacticError: ERROR at or near CLASS \ No newline at end of file diff --git a/tests/parser/mixed2.cl b/tests/parser/mixed2.cl new file mode 100644 index 00000000..f5477e0b --- /dev/null +++ b/tests/parser/mixed2.cl @@ -0,0 +1,14 @@ +class Main { + main(): Object { + (new Alpha).print() + }; + +}; + +(* Class names must begin with uppercase letters *) +class alpha inherits IO { + print() : Object { + out_string("reached!!\n"); + }; +}; + diff --git a/tests/parser/mixed2_error.txt b/tests/parser/mixed2_error.txt new file mode 100644 index 00000000..b5613c52 --- /dev/null +++ b/tests/parser/mixed2_error.txt @@ -0,0 +1 @@ +(9, 7) - SyntacticError: ERROR at or near "alpha" \ No newline at end of file diff --git a/tests/parser/mixed3.cl b/tests/parser/mixed3.cl new file mode 100644 index 00000000..1bdcad74 --- /dev/null +++ b/tests/parser/mixed3.cl @@ -0,0 +1,40 @@ +class Main inherits IO { + main() : Object { + { + out_string("Enter a number to check if number is prime\n"); + let i : Int <- in_int() in { + if(i <= 1) then { + out_string("Invalid Input\n"); + abort(); + } else { + if (isPrime(i) = 1) then + out_string("Number is prime\n") + else + out_string("Number is composite\n") + fi; + } + fi; + }; + } + }; + + mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. + i - (i/k)*k + }; + + isPrime(i : Int) : Int { + { + let x : Int <- 2, + c : Int <- 1 in + { + while (not (x = i)) loop + if (mod(i, x) = 0) then { + c <- 0; + x <- i; + } else x <- x + 1 fi + pool; + c; + }; + } + }; +}; diff --git a/tests/parser/mixed3_error.txt b/tests/parser/mixed3_error.txt new file mode 100644 index 00000000..159bdca6 --- /dev/null +++ b/tests/parser/mixed3_error.txt @@ -0,0 +1 @@ +(21, 18) - SyntacticError: ERROR at or near ")" \ No newline at end of file diff --git a/tests/parser/mixed4.cl b/tests/parser/mixed4.cl new file mode 100644 index 00000000..e752253b --- /dev/null +++ b/tests/parser/mixed4.cl @@ -0,0 +1,21 @@ +class Main inherits IO { + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(Main : Int); -- the parser correctly catches the error here + i <- i - 1; + } + pool; + y; + } + }; +}; diff --git a/tests/parser/mixed4_error.txt b/tests/parser/mixed4_error.txt new file mode 100644 index 00000000..2349f28a --- /dev/null +++ b/tests/parser/mixed4_error.txt @@ -0,0 +1 @@ +(14, 41) - SyntacticError: ERROR at or near "Main" \ No newline at end of file diff --git a/tests/parser/mixed5.cl b/tests/parser/mixed5.cl new file mode 100644 index 00000000..c9176a89 --- /dev/null +++ b/tests/parser/mixed5.cl @@ -0,0 +1,20 @@ +class Main inherits IO { + str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(); + i <- i - 1; + } + y; + } + }; +} diff --git a/tests/parser/mixed5_error.txt b/tests/parser/mixed5_error.txt new file mode 100644 index 00000000..443037ec --- /dev/null +++ b/tests/parser/mixed5_error.txt @@ -0,0 +1 @@ +(2, 9) - SyntacticError: ERROR at or near ASSIGN \ No newline at end of file diff --git a/tests/parser/mixed6.cl b/tests/parser/mixed6.cl new file mode 100644 index 00000000..5da80da3 --- /dev/null +++ b/tests/parser/mixed6.cl @@ -0,0 +1,5 @@ +classs Doom { + i : Int <- 0; + main() : Object { + if i = 0 then out_string("This is da real *h*t") + diff --git a/tests/parser/test4_error.txt b/tests/parser/mixed6_error.txt similarity index 100% rename from tests/parser/test4_error.txt rename to tests/parser/mixed6_error.txt diff --git a/tests/parser/operation1.cl b/tests/parser/operation1.cl new file mode 100644 index 00000000..d38eb72d --- /dev/null +++ b/tests/parser/operation1.cl @@ -0,0 +1,101 @@ +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Missing ')' + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a)/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/operation1_error.txt b/tests/parser/operation1_error.txt new file mode 100644 index 00000000..b3020239 --- /dev/null +++ b/tests/parser/operation1_error.txt @@ -0,0 +1 @@ +(74, 5) - SyntacticError: ERROR at or near "}" \ No newline at end of file diff --git a/tests/parser/operation2.cl b/tests/parser/operation2.cl new file mode 100644 index 00000000..2dc62835 --- /dev/null +++ b/tests/parser/operation2.cl @@ -0,0 +1,101 @@ +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Type identifiers starts with a uppercase letter + in isvoid (3 + a * (x / w + new int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/operation2_error.txt b/tests/parser/operation2_error.txt new file mode 100644 index 00000000..37b458f3 --- /dev/null +++ b/tests/parser/operation2_error.txt @@ -0,0 +1 @@ +(73, 41) - SyntacticError: ERROR at or near "int" \ No newline at end of file diff --git a/tests/parser/operation3.cl b/tests/parser/operation3.cl new file mode 100644 index 00000000..61d6cbfa --- /dev/null +++ b/tests/parser/operation3.cl @@ -0,0 +1,101 @@ +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Object identifiers starts with a lowercase letter + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~Mazinger_Z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/operation3_error.txt b/tests/parser/operation3_error.txt new file mode 100644 index 00000000..6b266f3f --- /dev/null +++ b/tests/parser/operation3_error.txt @@ -0,0 +1 @@ +(73, 81) - SyntacticError: ERROR at or near "Mazinger_Z" \ No newline at end of file diff --git a/tests/parser/operation4.cl b/tests/parser/operation4.cl new file mode 100644 index 00000000..bae7de5b --- /dev/null +++ b/tests/parser/operation4.cl @@ -0,0 +1,101 @@ +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Double "+" + in isvoid (3 + a * (x / w++ new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/tests/parser/operation4_error.txt b/tests/parser/operation4_error.txt new file mode 100644 index 00000000..e0ebb098 --- /dev/null +++ b/tests/parser/operation4_error.txt @@ -0,0 +1 @@ +(73, 35) - SyntacticError: ERROR at or near "+" \ No newline at end of file diff --git a/tests/parser/prod.cl b/tests/parser/prod.cl deleted file mode 100644 index effe5a7c..00000000 --- a/tests/parser/prod.cl +++ /dev/null @@ -1,21 +0,0 @@ -class Main inherits IO { - main() : Object { - { - out_string("Enter number of numbers to multiply\n"); - out_int(prod(in_int())); - out_string("\n"); - } - }; - - prod(i : Int) : Int { - let y : Int <- 1 in { - while (not (i = 0) ) loop { - out_string("Enter Number: "); - y <- y * in_int(Main : Int); -- the parser correctly catches the error here - i <- i - 1; - } - pool; - y; - } - }; -}; diff --git a/tests/parser/prod_error.txt b/tests/parser/prod_error.txt deleted file mode 100644 index ab4e7867..00000000 --- a/tests/parser/prod_error.txt +++ /dev/null @@ -1 +0,0 @@ -(14, 23) - SyntacticError: ERROR at or near "Main" \ No newline at end of file diff --git a/tests/parser/program1.cl b/tests/parser/program1.cl new file mode 100644 index 00000000..8e5cf617 --- /dev/null +++ b/tests/parser/program1.cl @@ -0,0 +1 @@ +(* A Cool program can't be empty *) \ No newline at end of file diff --git a/tests/parser/program1_error.txt b/tests/parser/program1_error.txt new file mode 100644 index 00000000..de00ac46 --- /dev/null +++ b/tests/parser/program1_error.txt @@ -0,0 +1 @@ +(0, 0) - SyntacticError: ERROR at or near EOF \ No newline at end of file diff --git a/tests/parser/program2.cl b/tests/parser/program2.cl new file mode 100644 index 00000000..f8b16779 --- /dev/null +++ b/tests/parser/program2.cl @@ -0,0 +1,20 @@ +(* Cool programs are sets of classes *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +-- Missing semicolon +class Test { + testing(): Int { + 2 + 2 + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/program2_error.txt b/tests/parser/program2_error.txt new file mode 100644 index 00000000..94ba8df6 --- /dev/null +++ b/tests/parser/program2_error.txt @@ -0,0 +1 @@ +(16, 1) - SyntacticError: ERROR at or near CLASS \ No newline at end of file diff --git a/tests/parser/program3.cl b/tests/parser/program3.cl new file mode 100644 index 00000000..e27889c5 --- /dev/null +++ b/tests/parser/program3.cl @@ -0,0 +1,24 @@ +(* Cool programs are sets of classes *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + testing(): Int { + 2 + 2 + }; +}; + +-- Only classes +suma(a: Int, b: Int) int { + a + b +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/program3_error.txt b/tests/parser/program3_error.txt new file mode 100644 index 00000000..dd3b3947 --- /dev/null +++ b/tests/parser/program3_error.txt @@ -0,0 +1 @@ +(16, 1) - SyntacticError: ERROR at or near "suma" \ No newline at end of file diff --git a/tests/parser/test2.cl b/tests/parser/test2.cl deleted file mode 100644 index 8fdb792e..00000000 --- a/tests/parser/test2.cl +++ /dev/null @@ -1,20 +0,0 @@ -class Main inherits IO { - str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - main() : Object { - { - out_string("Enter number of numbers to multiply\n"); - out_int(prod(in_int())); - out_string("\n"); - } - }; - prod(i : Int) : Int { - let y : Int <- 1 in { - while (not (i = 0) ) loop { - out_string("Enter Number: "); - y <- y * in_int(); - i <- i - 1; - } - y; - } - }; -} diff --git a/tests/parser/test2_error.txt b/tests/parser/test2_error.txt deleted file mode 100644 index 2bfe70f3..00000000 --- a/tests/parser/test2_error.txt +++ /dev/null @@ -1,4 +0,0 @@ -(2, 6) - SyntacticError: ERROR at or near "<-" -(17, 4) - SyntacticError: ERROR at or near "y" -(21, 1) - SyntacticError: ERROR at or near EOF - diff --git a/tests/parser/test4.cl b/tests/parser/test4.cl deleted file mode 100644 index aad6c503..00000000 --- a/tests/parser/test4.cl +++ /dev/null @@ -1,5 +0,0 @@ -classs Doom { - i : Int <- 0; - main() : Object { - if i = 0 then out_string("This is da real *h*t") - diff --git a/tests/parser_test.py b/tests/parser_test.py index 9376d2b6..129c0f20 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -3,11 +3,11 @@ from utils import compare_errors tests_dir = __file__.rpartition('/')[0] + '/parser/' -tests = [(tests_dir + file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -@pytest.mark.run(order=2) @pytest.mark.parser @pytest.mark.error +@pytest.mark.run(order=2) @pytest.mark.parametrize("cool_file", tests) def test_parser_errors(compiler_path, cool_file): - compare_errors(compiler_path, cool_file, cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file diff --git a/tests/semantic/arithmetic1.cl b/tests/semantic/arithmetic1.cl new file mode 100644 index 00000000..bf94eb19 --- /dev/null +++ b/tests/semantic/arithmetic1.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 * 2 / 3 - 4 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x + new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic10.cl b/tests/semantic/arithmetic10.cl new file mode 100644 index 00000000..bbfe6cdb --- /dev/null +++ b/tests/semantic/arithmetic10.cl @@ -0,0 +1,15 @@ +(* +The expression ~ is the integer +complement of . The expression must have static type Int and the entire expression +has static type Int. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in ~new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic10_error.txt b/tests/semantic/arithmetic10_error.txt new file mode 100644 index 00000000..b2be0476 --- /dev/null +++ b/tests/semantic/arithmetic10_error.txt @@ -0,0 +1 @@ +(13, 19) - TypeError: Inferred type Int of initialization of attribute test does not conform to declared type Bool. \ No newline at end of file diff --git a/tests/semantic/arithmetic11.cl b/tests/semantic/arithmetic11.cl new file mode 100644 index 00000000..fc067dc1 --- /dev/null +++ b/tests/semantic/arithmetic11.cl @@ -0,0 +1,14 @@ +(* +The expression not is the boolean complement of . The expression + must have static type Bool and the entire expression has static type Bool. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in not 1 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic11_error.txt b/tests/semantic/arithmetic11_error.txt new file mode 100644 index 00000000..bb4b8e1c --- /dev/null +++ b/tests/semantic/arithmetic11_error.txt @@ -0,0 +1 @@ +(13, 24) - TypeError: Argument of 'not' has type Int instead of Bool. \ No newline at end of file diff --git a/tests/semantic/arithmetic12.cl b/tests/semantic/arithmetic12.cl new file mode 100644 index 00000000..2e012fc4 --- /dev/null +++ b/tests/semantic/arithmetic12.cl @@ -0,0 +1,14 @@ +(* +The expression not is the boolean complement of . The expression + must have static type Bool and the entire expression has static type Bool. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in not 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic12_error.txt b/tests/semantic/arithmetic12_error.txt new file mode 100644 index 00000000..d25eab65 --- /dev/null +++ b/tests/semantic/arithmetic12_error.txt @@ -0,0 +1 @@ +(12, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. \ No newline at end of file diff --git a/tests/semantic/arithmetic1_error.txt b/tests/semantic/arithmetic1_error.txt new file mode 100644 index 00000000..a74ebf3d --- /dev/null +++ b/tests/semantic/arithmetic1_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int + String diff --git a/tests/semantic/arithmetic2.cl b/tests/semantic/arithmetic2.cl new file mode 100644 index 00000000..59532573 --- /dev/null +++ b/tests/semantic/arithmetic2.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 + 2 * 3 / 4 - new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x - new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic2_error.txt b/tests/semantic/arithmetic2_error.txt new file mode 100644 index 00000000..2c7952af --- /dev/null +++ b/tests/semantic/arithmetic2_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int - String diff --git a/tests/semantic/arithmetic3.cl b/tests/semantic/arithmetic3.cl new file mode 100644 index 00000000..b208957f --- /dev/null +++ b/tests/semantic/arithmetic3.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 - 2 + 3 * 4 / new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x / new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic3_error.txt b/tests/semantic/arithmetic3_error.txt new file mode 100644 index 00000000..81d88331 --- /dev/null +++ b/tests/semantic/arithmetic3_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int / String diff --git a/tests/semantic/arithmetic4.cl b/tests/semantic/arithmetic4.cl new file mode 100644 index 00000000..2c7dd4fc --- /dev/null +++ b/tests/semantic/arithmetic4.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic4_error.txt b/tests/semantic/arithmetic4_error.txt new file mode 100644 index 00000000..1ca6df02 --- /dev/null +++ b/tests/semantic/arithmetic4_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int * String \ No newline at end of file diff --git a/tests/semantic/arithmetic5.cl b/tests/semantic/arithmetic5.cl new file mode 100644 index 00000000..bc08c6e8 --- /dev/null +++ b/tests/semantic/arithmetic5.cl @@ -0,0 +1,11 @@ +--The static type of the expression is Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic5_error.txt b/tests/semantic/arithmetic5_error.txt new file mode 100644 index 00000000..dd534684 --- /dev/null +++ b/tests/semantic/arithmetic5_error.txt @@ -0,0 +1 @@ +(9, 19) - TypeError: Inferred type Int of initialization of attribute test does not conform to declared type Bool. diff --git a/tests/semantic/arithmetic6.cl b/tests/semantic/arithmetic6.cl new file mode 100644 index 00000000..a0c3d03f --- /dev/null +++ b/tests/semantic/arithmetic6.cl @@ -0,0 +1,11 @@ + --The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; diff --git a/tests/semantic/arithmetic6_error.txt b/tests/semantic/arithmetic6_error.txt new file mode 100644 index 00000000..2e43dfc1 --- /dev/null +++ b/tests/semantic/arithmetic6_error.txt @@ -0,0 +1 @@ +(10, 22) - TypeError: non-Int arguments: Int <= String diff --git a/tests/semantic/arithmetic7.cl b/tests/semantic/arithmetic7.cl new file mode 100644 index 00000000..c00c75cd --- /dev/null +++ b/tests/semantic/arithmetic7.cl @@ -0,0 +1,12 @@ + --The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; + diff --git a/tests/semantic/arithmetic7_error.txt b/tests/semantic/arithmetic7_error.txt new file mode 100644 index 00000000..6f353711 --- /dev/null +++ b/tests/semantic/arithmetic7_error.txt @@ -0,0 +1 @@ +(10, 22) - TypeError: non-Int arguments: Int < String diff --git a/tests/semantic/arithmetic8.cl b/tests/semantic/arithmetic8.cl new file mode 100644 index 00000000..3210bdb8 --- /dev/null +++ b/tests/semantic/arithmetic8.cl @@ -0,0 +1,13 @@ + --The rules are exactly the same as for the binary arithmetic operations, except that the result is a Bool. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; + + diff --git a/tests/semantic/arithmetic8_error.txt b/tests/semantic/arithmetic8_error.txt new file mode 100644 index 00000000..ebcaa379 --- /dev/null +++ b/tests/semantic/arithmetic8_error.txt @@ -0,0 +1 @@ +(9, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/arithmetic9.cl b/tests/semantic/arithmetic9.cl new file mode 100644 index 00000000..95579e13 --- /dev/null +++ b/tests/semantic/arithmetic9.cl @@ -0,0 +1,15 @@ +(* +The expression ~ is the integer +complement of . The expression must have static type Int and the entire expression +has static type Int. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 + ~new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic9_error.txt b/tests/semantic/arithmetic9_error.txt new file mode 100644 index 00000000..99fafbbf --- /dev/null +++ b/tests/semantic/arithmetic9_error.txt @@ -0,0 +1 @@ +(14, 25) - TypeError: Argument of '~' has type String instead of Int. \ No newline at end of file diff --git a/tests/semantic/assignment1.cl b/tests/semantic/assignment1.cl new file mode 100644 index 00000000..19ab7021 --- /dev/null +++ b/tests/semantic/assignment1.cl @@ -0,0 +1,7 @@ +--The static type of the expression must conform to the declared type of the identifier + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: Int <- "String"; +}; diff --git a/tests/semantic/assignment1_error.txt b/tests/semantic/assignment1_error.txt new file mode 100644 index 00000000..6eb88301 --- /dev/null +++ b/tests/semantic/assignment1_error.txt @@ -0,0 +1 @@ +(6, 18) - TypeError: Inferred type String of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/assignment2.cl b/tests/semantic/assignment2.cl new file mode 100644 index 00000000..cace221a --- /dev/null +++ b/tests/semantic/assignment2.cl @@ -0,0 +1,13 @@ +--The static type of an assignment is the static type of . + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A): B { a <- new C }; + test2(a: A): D { a <- new C }; +}; diff --git a/tests/semantic/assignment2_error.txt b/tests/semantic/assignment2_error.txt new file mode 100644 index 00000000..ed10b7f3 --- /dev/null +++ b/tests/semantic/assignment2_error.txt @@ -0,0 +1 @@ +(12, 22) - TypeError: Inferred return type C of method test2 does not conform to declared return type D. diff --git a/tests/semantic/assignment3.cl b/tests/semantic/assignment3.cl new file mode 100644 index 00000000..eba0d69e --- /dev/null +++ b/tests/semantic/assignment3.cl @@ -0,0 +1,14 @@ +--The static type of an assignment is the static type of . + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A; + b: B <- a <- new C; + d: D <- a <- new C; +}; diff --git a/tests/semantic/assignment3_error.txt b/tests/semantic/assignment3_error.txt new file mode 100644 index 00000000..bc9a718c --- /dev/null +++ b/tests/semantic/assignment3_error.txt @@ -0,0 +1 @@ +(13, 13) - TypeError: Inferred type C of initialization of attribute d does not conform to declared type D. \ No newline at end of file diff --git a/tests/semantic/attributes1.cl b/tests/semantic/attributes1.cl new file mode 100644 index 00000000..3fa0440e --- /dev/null +++ b/tests/semantic/attributes1.cl @@ -0,0 +1,13 @@ +--The static type of the expression must conform to the declared type of the attribute. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: IO <- new Main; + test2: B <- new A; + + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/attributes1_error.txt b/tests/semantic/attributes1_error.txt new file mode 100644 index 00000000..9cb8460c --- /dev/null +++ b/tests/semantic/attributes1_error.txt @@ -0,0 +1 @@ +(10, 17) - TypeError: Inferred type A of initialization of attribute test2 does not conform to declared type B. diff --git a/tests/semantic/attributes2.cl b/tests/semantic/attributes2.cl new file mode 100644 index 00000000..7937c2cc --- /dev/null +++ b/tests/semantic/attributes2.cl @@ -0,0 +1,13 @@ +--The static type of the expression must conform to the declared type of the attribute. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: IO <- new Main; + test2: C <- new D; + + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/attributes2_error.txt b/tests/semantic/attributes2_error.txt new file mode 100644 index 00000000..6d601b7c --- /dev/null +++ b/tests/semantic/attributes2_error.txt @@ -0,0 +1 @@ +(10, 17) - TypeError: Inferred type D of initialization of attribute test2 does not conform to declared type C. diff --git a/tests/semantic/attributes3.cl b/tests/semantic/attributes3.cl new file mode 100644 index 00000000..8a67decd --- /dev/null +++ b/tests/semantic/attributes3.cl @@ -0,0 +1,25 @@ +--Attributes are local to the class in which they are defined or inherited. + +class A { + a: Int <- 5; + test(x1: Int, y1: Int): Int { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then x + y else x - y fi; + } + }; +}; +class B inherits A { + b: Bool <- true; +}; +class C inherits B { + c: String <- "C"; +}; +class D inherits B { + d: IO <- new Main.main(); +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!") }; +}; \ No newline at end of file diff --git a/tests/semantic/attributes3_error.txt b/tests/semantic/attributes3_error.txt new file mode 100644 index 00000000..6195c816 --- /dev/null +++ b/tests/semantic/attributes3_error.txt @@ -0,0 +1 @@ +(9, 16) - NameError: Undeclared identifier b. diff --git a/tests/semantic/attributes4.cl b/tests/semantic/attributes4.cl new file mode 100644 index 00000000..a7f63adb --- /dev/null +++ b/tests/semantic/attributes4.cl @@ -0,0 +1,39 @@ +--Attributes are local to the class in which they are defined or inherited. + +class A { + a: Int <- 5; +}; +class B inherits A { + b: Bool <- true; + test(x1: Int, y1: Int): Int { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then x + y else x - y fi; + } + }; +}; +class D inherits B { + d: IO <- new Main.main(); + test3(x1: Int, y1: Int): IO { + let x: Int <- x1, y: Int <-y1, c: String <- "C" in { + x <- x + a; + y <- y + a; + if b then new IO.out_string(c) else d fi; + } + }; +}; +class C inherits B { + c: String <- "C"; + test2(x1: Int, y1: Int): IO { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then new IO.out_string(c) else d fi; + } + }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!") }; +}; \ No newline at end of file diff --git a/tests/semantic/attributes4_error.txt b/tests/semantic/attributes4_error.txt new file mode 100644 index 00000000..fa5fcfa8 --- /dev/null +++ b/tests/semantic/attributes4_error.txt @@ -0,0 +1 @@ +(32, 49) - NameError: Undeclared identifier d. \ No newline at end of file diff --git a/tests/semantic/basics1.cl b/tests/semantic/basics1.cl new file mode 100644 index 00000000..32ae1656 --- /dev/null +++ b/tests/semantic/basics1.cl @@ -0,0 +1,10 @@ +-- It is an error to redefine the IO class. + +class IO { + scan(): String { ":)" }; + print(s: String): IO { new IO }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/basics1_error.txt b/tests/semantic/basics1_error.txt new file mode 100644 index 00000000..676f5049 --- /dev/null +++ b/tests/semantic/basics1_error.txt @@ -0,0 +1 @@ +(3, 7) - SemanticError: Redefinition of basic class IO. diff --git a/tests/semantic/basics2.cl b/tests/semantic/basics2.cl new file mode 100644 index 00000000..cf2b1cd2 --- /dev/null +++ b/tests/semantic/basics2.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Int. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits Int { + is_prime(): Bool { false }; +}; diff --git a/tests/semantic/basics2_error.txt b/tests/semantic/basics2_error.txt new file mode 100644 index 00000000..69a3b681 --- /dev/null +++ b/tests/semantic/basics2_error.txt @@ -0,0 +1 @@ +(7, 18) - SemanticError: Class A cannot inherit class Int. diff --git a/tests/semantic/basics3.cl b/tests/semantic/basics3.cl new file mode 100644 index 00000000..fef017a8 --- /dev/null +++ b/tests/semantic/basics3.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Int. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Int { + is_prime(): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics3_error.txt b/tests/semantic/basics3_error.txt new file mode 100644 index 00000000..d8f80cb1 --- /dev/null +++ b/tests/semantic/basics3_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class Int. diff --git a/tests/semantic/basics4.cl b/tests/semantic/basics4.cl new file mode 100644 index 00000000..9266ec79 --- /dev/null +++ b/tests/semantic/basics4.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine String. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits String { + is_palindrome(): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics4_error.txt b/tests/semantic/basics4_error.txt new file mode 100644 index 00000000..d5cd4c3d --- /dev/null +++ b/tests/semantic/basics4_error.txt @@ -0,0 +1 @@ +(7, 18) - SemanticError: Class A cannot inherit class String. diff --git a/tests/semantic/basics5.cl b/tests/semantic/basics5.cl new file mode 100644 index 00000000..bad5eff1 --- /dev/null +++ b/tests/semantic/basics5.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine String. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class String { + is_palindrome(): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics5_error.txt b/tests/semantic/basics5_error.txt new file mode 100644 index 00000000..8437accf --- /dev/null +++ b/tests/semantic/basics5_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class String. diff --git a/tests/semantic/basics6.cl b/tests/semantic/basics6.cl new file mode 100644 index 00000000..47266ebe --- /dev/null +++ b/tests/semantic/basics6.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits Bool { + xor(b: Bool): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics6_error.txt b/tests/semantic/basics6_error.txt new file mode 100644 index 00000000..b4d22da1 --- /dev/null +++ b/tests/semantic/basics6_error.txt @@ -0,0 +1 @@ +(7, 18) - SemanticError: Class A cannot inherit class Bool. diff --git a/tests/semantic/basics7.cl b/tests/semantic/basics7.cl new file mode 100644 index 00000000..0f30aaec --- /dev/null +++ b/tests/semantic/basics7.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Bool { + xor(b: Bool): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics7_error.txt b/tests/semantic/basics7_error.txt new file mode 100644 index 00000000..92660ab9 --- /dev/null +++ b/tests/semantic/basics7_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class Bool. diff --git a/tests/semantic/basics8.cl b/tests/semantic/basics8.cl new file mode 100644 index 00000000..3b9697d4 --- /dev/null +++ b/tests/semantic/basics8.cl @@ -0,0 +1,9 @@ +-- It is an error redefine Object. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Object { + xor(b: Bool): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics8_error.txt b/tests/semantic/basics8_error.txt new file mode 100644 index 00000000..652f47b3 --- /dev/null +++ b/tests/semantic/basics8_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class Object. diff --git a/tests/semantic/blocks1.cl b/tests/semantic/blocks1.cl new file mode 100644 index 00000000..1e928908 --- /dev/null +++ b/tests/semantic/blocks1.cl @@ -0,0 +1,31 @@ +--The static type of a block is the static type of the last expression. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- { + new A; + { + new B; + { + new C; + { + new D; + { + new E; + { + new F; + }; + }; + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/tests/semantic/blocks1_error.txt b/tests/semantic/blocks1_error.txt new file mode 100644 index 00000000..2f0e2caf --- /dev/null +++ b/tests/semantic/blocks1_error.txt @@ -0,0 +1 @@ +(13, 16) - TypeError: Inferred type F of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/case1.cl b/tests/semantic/case1.cl new file mode 100644 index 00000000..82c6a4d6 --- /dev/null +++ b/tests/semantic/case1.cl @@ -0,0 +1,23 @@ +--For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: B <- case 0 of + b: Bool => new F; + i: Int => new E; + esac; +}; diff --git a/tests/semantic/case1_error.txt b/tests/semantic/case1_error.txt new file mode 100644 index 00000000..f05ce31b --- /dev/null +++ b/tests/semantic/case1_error.txt @@ -0,0 +1 @@ +(19, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/case2.cl b/tests/semantic/case2.cl new file mode 100644 index 00000000..ae97b41d --- /dev/null +++ b/tests/semantic/case2.cl @@ -0,0 +1,23 @@ +-- The variables declared on each branch of a case must all have distinct types. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: A <- case 0 of + b: Bool => new F; + i: Bool => new E; + esac; +}; \ No newline at end of file diff --git a/tests/semantic/case2_error.txt b/tests/semantic/case2_error.txt new file mode 100644 index 00000000..302fec38 --- /dev/null +++ b/tests/semantic/case2_error.txt @@ -0,0 +1 @@ +(21, 20) - SemanticError: Duplicate branch Bool in case statement. \ No newline at end of file diff --git a/tests/semantic/case3.cl b/tests/semantic/case3.cl new file mode 100644 index 00000000..da79bbfe --- /dev/null +++ b/tests/semantic/case3.cl @@ -0,0 +1,23 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: A <- case 0 of + b: Bool => new F; + i: Ball => new E; + esac; +}; \ No newline at end of file diff --git a/tests/semantic/case3_error.txt b/tests/semantic/case3_error.txt new file mode 100644 index 00000000..fea261e5 --- /dev/null +++ b/tests/semantic/case3_error.txt @@ -0,0 +1 @@ +(21, 20) - TypeError: Class Ball of case branch is undefined. \ No newline at end of file diff --git a/tests/semantic/class1.cl b/tests/semantic/class1.cl new file mode 100644 index 00000000..ed83da9d --- /dev/null +++ b/tests/semantic/class1.cl @@ -0,0 +1,9 @@ +-- Classes may not be redefined. + +class Repeat { + sum(a: Int, b: Int): Int { a + b }; +}; + +class Repeat { + mult(a: Int, b: Int): Int { a * b }; +}; \ No newline at end of file diff --git a/tests/semantic/class1_error.txt b/tests/semantic/class1_error.txt new file mode 100644 index 00000000..19c50767 --- /dev/null +++ b/tests/semantic/class1_error.txt @@ -0,0 +1,2 @@ +(7, 5) - SemanticError: Classes may not be redefined + diff --git a/tests/semantic/conditionals1.cl b/tests/semantic/conditionals1.cl new file mode 100644 index 00000000..3446a8b0 --- /dev/null +++ b/tests/semantic/conditionals1.cl @@ -0,0 +1,14 @@ +--The predicate must have static type Bool. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A <- if new F then new D else new C fi; +}; \ No newline at end of file diff --git a/tests/semantic/conditionals1_error.txt b/tests/semantic/conditionals1_error.txt new file mode 100644 index 00000000..b8634535 --- /dev/null +++ b/tests/semantic/conditionals1_error.txt @@ -0,0 +1 @@ +(13, 16) - TypeError: Predicate of 'if' does not have type Bool. diff --git a/tests/semantic/conditionals2.cl b/tests/semantic/conditionals2.cl new file mode 100644 index 00000000..9d6313d7 --- /dev/null +++ b/tests/semantic/conditionals2.cl @@ -0,0 +1,24 @@ +(* +Let T and F be the static types of the branches of the conditional. Then the static type of the +conditional is T t F. (think: Walk towards Object from each of T and F until the paths meet.) +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- if true then + new C + else + if false then new D + else new E fi + fi; + + test: B <- if not true then new F else new E fi; +}; diff --git a/tests/semantic/conditionals2_error.txt b/tests/semantic/conditionals2_error.txt new file mode 100644 index 00000000..d6f5fc30 --- /dev/null +++ b/tests/semantic/conditionals2_error.txt @@ -0,0 +1,2 @@ +(23, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. + diff --git a/tests/semantic/dispatch1.cl b/tests/semantic/dispatch1.cl new file mode 100644 index 00000000..1c0457fa --- /dev/null +++ b/tests/semantic/dispatch1.cl @@ -0,0 +1,33 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- new D.back("Hello ").back("World!"); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch1_error.txt b/tests/semantic/dispatch1_error.txt new file mode 100644 index 00000000..7fb22edc --- /dev/null +++ b/tests/semantic/dispatch1_error.txt @@ -0,0 +1 @@ +(32, 37) - AttributeError: Dispatch to undefined method back. diff --git a/tests/semantic/dispatch2.cl b/tests/semantic/dispatch2.cl new file mode 100644 index 00000000..5182912b --- /dev/null +++ b/tests/semantic/dispatch2.cl @@ -0,0 +1,34 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +the dispatch and the definition of f must have the same number of arguments +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: Int <- new D.back("Hello ").g(2, 2); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch2_error.txt b/tests/semantic/dispatch2_error.txt new file mode 100644 index 00000000..a86c3534 --- /dev/null +++ b/tests/semantic/dispatch2_error.txt @@ -0,0 +1 @@ +(33, 39) - SemanticError: Method g called with wrong number of arguments. diff --git a/tests/semantic/dispatch3.cl b/tests/semantic/dispatch3.cl new file mode 100644 index 00000000..ecb1535d --- /dev/null +++ b/tests/semantic/dispatch3.cl @@ -0,0 +1,36 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +the static type of the ith actual parameter must conform to the declared type of the ith formal parameter. +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; + + alphabet(a: A, b: B, c: C): D { self }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- new D.alphabet(new D, new D, new D.back("Hello ")).back("World!"); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch3_error.txt b/tests/semantic/dispatch3_error.txt new file mode 100644 index 00000000..0def5cf0 --- /dev/null +++ b/tests/semantic/dispatch3_error.txt @@ -0,0 +1 @@ +(35, 45) - TypeError: In call of method alphabet, type B of parameter c does not conform to declared type C. diff --git a/tests/semantic/dispatch4.cl b/tests/semantic/dispatch4.cl new file mode 100644 index 00000000..9cadd833 --- /dev/null +++ b/tests/semantic/dispatch4.cl @@ -0,0 +1,36 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +If f has return type B and B is a class name, then the static type of the dispatch is B. +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; + + alphabet(a: A, b: B, c: C): D { self }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: D <- new D.alphabet(new D, new D.back("Hello "), new C).back("World!"); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch4_error.txt b/tests/semantic/dispatch4_error.txt new file mode 100644 index 00000000..9699f166 --- /dev/null +++ b/tests/semantic/dispatch4_error.txt @@ -0,0 +1 @@ +(35, 16) - TypeError: Inferred type B of initialization of attribute test does not conform to declared type D. \ No newline at end of file diff --git a/tests/semantic/dispatch5.cl b/tests/semantic/dispatch5.cl new file mode 100644 index 00000000..b4437b1b --- /dev/null +++ b/tests/semantic/dispatch5.cl @@ -0,0 +1,31 @@ +(* +(,...,) is shorthand for self.(,...,). +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; + sum(m: Int, n: Int, p: Int): Int { m + n + p }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + + back(s: String): B { { + out_string(s); + g(2); + sum(1, 2, 3); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/dispatch5_error.txt b/tests/semantic/dispatch5_error.txt new file mode 100644 index 00000000..d26bf34a --- /dev/null +++ b/tests/semantic/dispatch5_error.txt @@ -0,0 +1 @@ +(24, 9) - AttributeError: Dispatch to undefined method sum. diff --git a/tests/semantic/dispatch6.cl b/tests/semantic/dispatch6.cl new file mode 100644 index 00000000..fcc033f2 --- /dev/null +++ b/tests/semantic/dispatch6.cl @@ -0,0 +1,32 @@ +(* +e@B.f() invokes the method +f in class B on the object that is the value of e. For this form of dispatch, the static type to the left of +“@”must conform to the type specified to the right of “@”. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; + sum(m: Int, n: Int, p: Int): Int { m + n + p }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + sum(v: Int, w: Int, z: Int): Int { v - w - z }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A <- new D; + b: Int <- new D@B.sum(1, 2, 3); + test: Int <- a@B.sum(1, 2, 3); +}; diff --git a/tests/semantic/dispatch6_error.txt b/tests/semantic/dispatch6_error.txt new file mode 100644 index 00000000..ae9184b2 --- /dev/null +++ b/tests/semantic/dispatch6_error.txt @@ -0,0 +1 @@ +(31, 18) - TypeError: Expression type A does not conform to declared static dispatch type B. diff --git a/tests/semantic/eq1.cl b/tests/semantic/eq1.cl new file mode 100644 index 00000000..88f2a7ff --- /dev/null +++ b/tests/semantic/eq1.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + test: Bool <- 1 = new A; + y: Bool <- "1" = "2"; + z: Bool <- true = not false; +}; \ No newline at end of file diff --git a/tests/semantic/eq1_error.txt b/tests/semantic/eq1_error.txt new file mode 100644 index 00000000..f8142568 --- /dev/null +++ b/tests/semantic/eq1_error.txt @@ -0,0 +1 @@ +(14, 21) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq2.cl b/tests/semantic/eq2.cl new file mode 100644 index 00000000..d7685278 --- /dev/null +++ b/tests/semantic/eq2.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + test: Bool <- "1" = new B; + z: Bool <- true = not false; +}; diff --git a/tests/semantic/eq2_error.txt b/tests/semantic/eq2_error.txt new file mode 100644 index 00000000..a44ab0d5 --- /dev/null +++ b/tests/semantic/eq2_error.txt @@ -0,0 +1 @@ +(15, 23) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq3.cl b/tests/semantic/eq3.cl new file mode 100644 index 00000000..4dad693e --- /dev/null +++ b/tests/semantic/eq3.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + z: Bool <- true = not false; + test: Bool <- "true" = not false; +}; diff --git a/tests/semantic/eq3_error.txt b/tests/semantic/eq3_error.txt new file mode 100644 index 00000000..c4e27eb8 --- /dev/null +++ b/tests/semantic/eq3_error.txt @@ -0,0 +1 @@ +(16, 26) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq4.cl b/tests/semantic/eq4.cl new file mode 100644 index 00000000..11afc119 --- /dev/null +++ b/tests/semantic/eq4.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. The result is a Bool. +*) + +class A { }; +class B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + z: Bool <- new A = new B; + test: Int <- new A = new B; +}; diff --git a/tests/semantic/eq4_error.txt b/tests/semantic/eq4_error.txt new file mode 100644 index 00000000..3ead21d0 --- /dev/null +++ b/tests/semantic/eq4_error.txt @@ -0,0 +1 @@ +(16, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/features1.cl b/tests/semantic/features1.cl new file mode 100755 index 00000000..96dd8ebc --- /dev/null +++ b/tests/semantic/features1.cl @@ -0,0 +1,19 @@ +(* +No method name may be defined multiple times in +a class, and no attribute name may be defined multiple times in a class, but a method and an attribute +may have the same name. +*) + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): Int { 3 }; + + x: String <- ":)"; +}; \ No newline at end of file diff --git a/tests/semantic/features1_error.txt b/tests/semantic/features1_error.txt new file mode 100755 index 00000000..40033e9b --- /dev/null +++ b/tests/semantic/features1_error.txt @@ -0,0 +1 @@ +(18, 5) - SemanticError: Attribute x is multiply defined in class. \ No newline at end of file diff --git a/tests/semantic/features2.cl b/tests/semantic/features2.cl new file mode 100755 index 00000000..2db177f7 --- /dev/null +++ b/tests/semantic/features2.cl @@ -0,0 +1,19 @@ +(* +No method name may be defined multiple times in +a class, and no attribute name may be defined multiple times in a class, but a method and an attribute +may have the same name. +*) + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): String { "3" }; + + x(): String { ":)" }; +}; \ No newline at end of file diff --git a/tests/semantic/features2_error.txt b/tests/semantic/features2_error.txt new file mode 100755 index 00000000..117e0604 --- /dev/null +++ b/tests/semantic/features2_error.txt @@ -0,0 +1 @@ +(18, 5) - SemanticError: Method x is multiply defined. \ No newline at end of file diff --git a/tests/semantic/features3.cl b/tests/semantic/features3.cl new file mode 100755 index 00000000..a3b59259 --- /dev/null +++ b/tests/semantic/features3.cl @@ -0,0 +1,15 @@ +-- Missing type + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): Int { 3 }; + + c: Cadena; +}; \ No newline at end of file diff --git a/tests/semantic/features3_error.txt b/tests/semantic/features3_error.txt new file mode 100755 index 00000000..53f1abe2 --- /dev/null +++ b/tests/semantic/features3_error.txt @@ -0,0 +1 @@ +(14, 8) - TypeError: Class Cadena of attribute c is undefined. \ No newline at end of file diff --git a/tests/semantic/hello_world.cl b/tests/semantic/hello_world.cl deleted file mode 100755 index 0c818f90..00000000 --- a/tests/semantic/hello_world.cl +++ /dev/null @@ -1,5 +0,0 @@ -class Main inherits IO { - main(): IO { - out_string("Hello, World.\n") - }; -}; diff --git a/tests/semantic/inheritance1.cl b/tests/semantic/inheritance1.cl new file mode 100755 index 00000000..5adb59d9 --- /dev/null +++ b/tests/semantic/inheritance1.cl @@ -0,0 +1,19 @@ +--It is illegal to redefine attribute names. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): String { ":)" }; +}; + +class B inherits A { + x: Int; + + div(a: Int, b: Int): Int { a / b}; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance1_error.txt b/tests/semantic/inheritance1_error.txt new file mode 100755 index 00000000..ec5b504e --- /dev/null +++ b/tests/semantic/inheritance1_error.txt @@ -0,0 +1 @@ +(16, 5) - SemanticError: Attribute x is an attribute of an inherited class. \ No newline at end of file diff --git a/tests/semantic/inheritance2.cl b/tests/semantic/inheritance2.cl new file mode 100755 index 00000000..2ed46f37 --- /dev/null +++ b/tests/semantic/inheritance2.cl @@ -0,0 +1,19 @@ +--If C inherits from P, then P must have a class definition somewhere in the program. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class Alo { + x: Int <- 3; + + x(): String { "3" }; +}; + +class B inherits A { + div(a: Int, b: Int): Int { a / b}; + + x: String <- "2"; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance2_error.txt b/tests/semantic/inheritance2_error.txt new file mode 100755 index 00000000..1ec7669b --- /dev/null +++ b/tests/semantic/inheritance2_error.txt @@ -0,0 +1 @@ +(15, 18) - TypeError: Class B inherits from an undefined class A. \ No newline at end of file diff --git a/tests/semantic/inheritance3.cl b/tests/semantic/inheritance3.cl new file mode 100755 index 00000000..83a4e132 --- /dev/null +++ b/tests/semantic/inheritance3.cl @@ -0,0 +1,13 @@ +--The parent-child relation on classes defines a graph. This graph may not contain cycles. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A inherits A { + x: Int <- 3; + + x(): String { ":)" }; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance3_error.txt b/tests/semantic/inheritance3_error.txt new file mode 100644 index 00000000..d17ca7f4 --- /dev/null +++ b/tests/semantic/inheritance3_error.txt @@ -0,0 +1 @@ +(9, 18) - SemanticError: Class A, or an ancestor of A, is involved in an inheritance cycle. \ No newline at end of file diff --git a/tests/semantic/inheritance4.cl b/tests/semantic/inheritance4.cl new file mode 100755 index 00000000..efe6e9a6 --- /dev/null +++ b/tests/semantic/inheritance4.cl @@ -0,0 +1,19 @@ +--The parent-child relation on classes defines a graph. This graph may not contain cycles. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A inherits B { + x: Int <- 3; + + x(): String { ":)" }; +}; + +class B inherits A { + y: Int <- 2; + + div(a: Int, b: Int): Int { a / b}; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance4_error.txt b/tests/semantic/inheritance4_error.txt new file mode 100644 index 00000000..b437ec66 --- /dev/null +++ b/tests/semantic/inheritance4_error.txt @@ -0,0 +1 @@ +(15, 18) - SemanticError: Class B, or an ancestor of B, is involved in an inheritance cycle. \ No newline at end of file diff --git a/tests/semantic/inheritance5.cl b/tests/semantic/inheritance5.cl new file mode 100755 index 00000000..6650368c --- /dev/null +++ b/tests/semantic/inheritance5.cl @@ -0,0 +1,21 @@ +--The parent-child relation on classes defines a graph. This graph may not contain cycles. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A inherits B { + x: Int <- 3; + + x(): String { ":)" }; +}; + +class B inherits C { + y: Int <- 2; + + div(a: Int, b: Int): Int { a / b}; +}; + +class C inherits A { }; \ No newline at end of file diff --git a/tests/semantic/inheritance5_error.txt b/tests/semantic/inheritance5_error.txt new file mode 100644 index 00000000..da72ba54 --- /dev/null +++ b/tests/semantic/inheritance5_error.txt @@ -0,0 +1 @@ +(21, 18) - SemanticError: Class C, or an ancestor of C, is involved in an inheritance cycle. \ No newline at end of file diff --git a/tests/semantic/isvoid1.cl b/tests/semantic/isvoid1.cl new file mode 100644 index 00000000..072720d8 --- /dev/null +++ b/tests/semantic/isvoid1.cl @@ -0,0 +1,26 @@ +--evaluates to true if expr is void and evaluates to false if expr is not void. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- if isvoid new F then + new C + else + if false then new D + else new E fi + fi; + + test: B <- isvoid if isvoid new F then + new C + else + if false then new D + else new E fi + fi; +}; \ No newline at end of file diff --git a/tests/semantic/isvoid1_error.txt b/tests/semantic/isvoid1_error.txt new file mode 100644 index 00000000..0922de90 --- /dev/null +++ b/tests/semantic/isvoid1_error.txt @@ -0,0 +1 @@ +(20, 16) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/let1.cl b/tests/semantic/let1.cl new file mode 100644 index 00000000..26ef6302 --- /dev/null +++ b/tests/semantic/let1.cl @@ -0,0 +1,15 @@ +--The type of an initialization expression must conform to the declared type of the identifier. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: C <- new E in b; +}; \ No newline at end of file diff --git a/tests/semantic/let1_error.txt b/tests/semantic/let1_error.txt new file mode 100644 index 00000000..16ecf780 --- /dev/null +++ b/tests/semantic/let1_error.txt @@ -0,0 +1 @@ +(14, 76) - TypeError: Inferred type E of initialization of b does not conform to identifier's declared type C. diff --git a/tests/semantic/let2.cl b/tests/semantic/let2.cl new file mode 100644 index 00000000..c5956ead --- /dev/null +++ b/tests/semantic/let2.cl @@ -0,0 +1,15 @@ +--The type of let is the type of the body. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: A <- new E in b; +}; \ No newline at end of file diff --git a/tests/semantic/let2_error.txt b/tests/semantic/let2_error.txt new file mode 100644 index 00000000..b1e8a365 --- /dev/null +++ b/tests/semantic/let2_error.txt @@ -0,0 +1 @@ +(14, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/let3.cl b/tests/semantic/let3.cl new file mode 100644 index 00000000..8c0670ab --- /dev/null +++ b/tests/semantic/let3.cl @@ -0,0 +1,15 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: Cadena in new B; +}; \ No newline at end of file diff --git a/tests/semantic/let3_error.txt b/tests/semantic/let3_error.txt new file mode 100644 index 00000000..39c5315d --- /dev/null +++ b/tests/semantic/let3_error.txt @@ -0,0 +1 @@ +(14, 71) - TypeError: Class Cadena of let-bound identifier b is undefined. \ No newline at end of file diff --git a/tests/semantic/loops1.cl b/tests/semantic/loops1.cl new file mode 100644 index 00000000..de3a624d --- /dev/null +++ b/tests/semantic/loops1.cl @@ -0,0 +1,8 @@ +--The predicate must have static type Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + i: Int <- 1; + test: Object <- while "true" loop i <- i + 1 pool; +}; \ No newline at end of file diff --git a/tests/semantic/loops1_error.txt b/tests/semantic/loops1_error.txt new file mode 100644 index 00000000..b160214b --- /dev/null +++ b/tests/semantic/loops1_error.txt @@ -0,0 +1 @@ +(7, 27) - TypeError: Loop condition does not have type Bool. \ No newline at end of file diff --git a/tests/semantic/loops2.cl b/tests/semantic/loops2.cl new file mode 100644 index 00000000..dea69fa1 --- /dev/null +++ b/tests/semantic/loops2.cl @@ -0,0 +1,9 @@ +--The static type of a loop expression is Object. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + i: Int <- 1; + test: Object <- while not false loop i <- i + 1 pool; + test2: Int <- while not false loop i <- i + 1 pool; +}; diff --git a/tests/semantic/loops2_error.txt b/tests/semantic/loops2_error.txt new file mode 100644 index 00000000..9711cdf6 --- /dev/null +++ b/tests/semantic/loops2_error.txt @@ -0,0 +1 @@ +(8, 19) - TypeError: Inferred type Object of initialization of attribute test2 does not conform to declared type Int. diff --git a/tests/semantic/methods1.cl b/tests/semantic/methods1.cl new file mode 100644 index 00000000..d1203197 --- /dev/null +++ b/tests/semantic/methods1.cl @@ -0,0 +1,12 @@ +--The identifiers used in the formal parameter list must be distinct + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, a: B): Int { 4 }; +}; \ No newline at end of file diff --git a/tests/semantic/methods1_error.txt b/tests/semantic/methods1_error.txt new file mode 100644 index 00000000..06ab88a9 --- /dev/null +++ b/tests/semantic/methods1_error.txt @@ -0,0 +1 @@ +(11, 16) - SemanticError: Formal parameter a is multiply defined. diff --git a/tests/semantic/methods2.cl b/tests/semantic/methods2.cl new file mode 100644 index 00000000..3865f0e1 --- /dev/null +++ b/tests/semantic/methods2.cl @@ -0,0 +1,12 @@ +--The type of the method body must conform to the declared return type. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: B): C { new D }; +}; \ No newline at end of file diff --git a/tests/semantic/methods2_error.txt b/tests/semantic/methods2_error.txt new file mode 100644 index 00000000..f7e4a330 --- /dev/null +++ b/tests/semantic/methods2_error.txt @@ -0,0 +1 @@ +(11, 27) - TypeError: Inferred return type D of method test does not conform to declared return type C. diff --git a/tests/semantic/methods3.cl b/tests/semantic/methods3.cl new file mode 100644 index 00000000..b92faeb9 --- /dev/null +++ b/tests/semantic/methods3.cl @@ -0,0 +1,14 @@ +--A formal parameter hides any definition of an attribute of the same name. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: C <- new C; + test(a: D): D { a }; + test2(a: B): C { a }; +}; \ No newline at end of file diff --git a/tests/semantic/methods3_error.txt b/tests/semantic/methods3_error.txt new file mode 100644 index 00000000..1165b759 --- /dev/null +++ b/tests/semantic/methods3_error.txt @@ -0,0 +1 @@ +(13, 22) - TypeError: Inferred return type B of method test2 does not conform to declared return type C. diff --git a/tests/semantic/methods4.cl b/tests/semantic/methods4.cl new file mode 100644 index 00000000..be8fa36e --- /dev/null +++ b/tests/semantic/methods4.cl @@ -0,0 +1,19 @@ +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; +}; +class B inherits A { + f(x: Int, y: Object): Int { x }; +}; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/methods4_error.txt b/tests/semantic/methods4_error.txt new file mode 100644 index 00000000..9f1486de --- /dev/null +++ b/tests/semantic/methods4_error.txt @@ -0,0 +1 @@ +(12, 15) - SemanticError: In redefined method f, parameter type Object is different from original type Int. diff --git a/tests/semantic/methods5.cl b/tests/semantic/methods5.cl new file mode 100644 index 00000000..3905dfdd --- /dev/null +++ b/tests/semantic/methods5.cl @@ -0,0 +1,20 @@ +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; +}; +class B inherits A { + f(a: Int, b: Int): Object { a - b }; +}; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + diff --git a/tests/semantic/methods5_error.txt b/tests/semantic/methods5_error.txt new file mode 100644 index 00000000..8b6bdf36 --- /dev/null +++ b/tests/semantic/methods5_error.txt @@ -0,0 +1 @@ +(12, 24) - SemanticError: In redefined method f, return type Object is different from original return type Int. diff --git a/tests/semantic/methods6.cl b/tests/semantic/methods6.cl new file mode 100644 index 00000000..dd2b73da --- /dev/null +++ b/tests/semantic/methods6.cl @@ -0,0 +1,27 @@ +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int, w: Int, z: Int): Int { v + w + z }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/methods6_error.txt b/tests/semantic/methods6_error.txt new file mode 100644 index 00000000..8e32663b --- /dev/null +++ b/tests/semantic/methods6_error.txt @@ -0,0 +1 @@ +(22, 5) - SemanticError: Incompatible number of formal parameters in redefined method g. diff --git a/tests/semantic/methods7.cl b/tests/semantic/methods7.cl new file mode 100644 index 00000000..e5a01f68 --- /dev/null +++ b/tests/semantic/methods7.cl @@ -0,0 +1,12 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: Ball): Int { 4 }; +}; \ No newline at end of file diff --git a/tests/semantic/methods7_error.txt b/tests/semantic/methods7_error.txt new file mode 100644 index 00000000..472cbd9d --- /dev/null +++ b/tests/semantic/methods7_error.txt @@ -0,0 +1 @@ +(11, 19) - TypeError: Class Ball of formal parameter b is undefined. \ No newline at end of file diff --git a/tests/semantic/methods8.cl b/tests/semantic/methods8.cl new file mode 100644 index 00000000..3fccab54 --- /dev/null +++ b/tests/semantic/methods8.cl @@ -0,0 +1,12 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: B): Integrer { 4 }; +}; \ No newline at end of file diff --git a/tests/semantic/methods8_error.txt b/tests/semantic/methods8_error.txt new file mode 100644 index 00000000..dc9302ec --- /dev/null +++ b/tests/semantic/methods8_error.txt @@ -0,0 +1 @@ +(11, 23) - TypeError: Undefined return type Integrer in method test. \ No newline at end of file diff --git a/tests/semantic/new1.cl b/tests/semantic/new1.cl new file mode 100644 index 00000000..d007fc03 --- /dev/null +++ b/tests/semantic/new1.cl @@ -0,0 +1,31 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: F <- { + new A; + { + new Ball; + { + new C; + { + new D; + { + new E; + { + new F; + }; + }; + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/tests/semantic/new1_error.txt b/tests/semantic/new1_error.txt new file mode 100644 index 00000000..612a3d42 --- /dev/null +++ b/tests/semantic/new1_error.txt @@ -0,0 +1 @@ +(16, 17) - TypeError: 'new' used with undefined class Ball. \ No newline at end of file diff --git a/tests/semantic/self1.cl b/tests/semantic/self1.cl new file mode 100644 index 00000000..3387fd26 --- /dev/null +++ b/tests/semantic/self1.cl @@ -0,0 +1,11 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: Main): IO { self <- a }; +}; diff --git a/tests/semantic/self1_error.txt b/tests/semantic/self1_error.txt new file mode 100644 index 00000000..6beb3cda --- /dev/null +++ b/tests/semantic/self1_error.txt @@ -0,0 +1 @@ +(10, 30) - SemanticError: Cannot assign to 'self'. diff --git a/tests/semantic/self2.cl b/tests/semantic/self2.cl new file mode 100644 index 00000000..2e6921a9 --- /dev/null +++ b/tests/semantic/self2.cl @@ -0,0 +1,10 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(): IO { let self: Main <- new Main in self }; +}; diff --git a/tests/semantic/self2_error.txt b/tests/semantic/self2_error.txt new file mode 100644 index 00000000..20c883c9 --- /dev/null +++ b/tests/semantic/self2_error.txt @@ -0,0 +1 @@ +(9, 22) - SemanticError: 'self' cannot be bound in a 'let' expression. diff --git a/tests/semantic/self3.cl b/tests/semantic/self3.cl new file mode 100644 index 00000000..81709b4b --- /dev/null +++ b/tests/semantic/self3.cl @@ -0,0 +1,10 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(self: IO): IO { self }; +}; diff --git a/tests/semantic/self3_error.txt b/tests/semantic/self3_error.txt new file mode 100644 index 00000000..0ae38200 --- /dev/null +++ b/tests/semantic/self3_error.txt @@ -0,0 +1 @@ +(9, 10) - SemanticError: 'self' cannot be the name of a formal parameter. diff --git a/tests/semantic/self4.cl b/tests/semantic/self4.cl new file mode 100644 index 00000000..7c2b960c --- /dev/null +++ b/tests/semantic/self4.cl @@ -0,0 +1,10 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + self: IO <- self; +}; \ No newline at end of file diff --git a/tests/semantic/self4_error.txt b/tests/semantic/self4_error.txt new file mode 100644 index 00000000..c19ca400 --- /dev/null +++ b/tests/semantic/self4_error.txt @@ -0,0 +1 @@ +(9, 5) - SemanticError: 'self' cannot be the name of an attribute. diff --git a/tests/semantic_test.py b/tests/semantic_test.py index 2ec0819e..cac9cd78 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -1,13 +1,14 @@ import pytest import os -from utils import compare_errors +from utils import compare_errors, first_error_only_line tests_dir = __file__.rpartition('/')[0] + '/semantic/' -tests = [(tests_dir + file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -@pytest.mark.run(order=3) @pytest.mark.semantic @pytest.mark.error -@pytest.mark.parametrize("cool_file", []) +@pytest.mark.run(order=3) +@pytest.mark.parametrize("cool_file", tests) def test_semantic_errors(compiler_path, cool_file): - compare_errors(compiler_path, cool_file, cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ + cmp=first_error_only_line) \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 75c89682..961cf7cb 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -1,16 +1,21 @@ import subprocess import re + COMPILER_TIMEOUT = 'El compilador tarda mucho en responder.' +SPIM_TIMEOUT = 'El spim tarda mucho en responder.' TEST_MUST_FAIL = 'El test %s debe fallar al compilar' TEST_MUST_COMPILE = 'El test %s debe compilar' BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : - o no se encuentra en la 3ra linea''' + o no se encuentra en la 3ra linea\n\n%s''' UNEXPECTED_ERROR = 'Se esperaba un %s en (%d, %d). Su error fue un %s en (%d, %d)' +UNEXPECTED_OUTPUT = 'La salida de %s no es la esperada:\n%s\nEsperada:\n%s' + +ERROR_FORMAT = r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$' def parse_error(error: str): - merror = re.fullmatch(r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$', error) - assert merror, BAD_ERROR_FORMAT + merror = re.fullmatch(ERROR_FORMAT, error) + assert merror, BAD_ERROR_FORMAT % error return (t(x) for t, x in zip([int, int, str, str], merror.groups())) @@ -23,25 +28,64 @@ def first_error(compiler_output: list, errors: list): assert line == oline and column == ocolumn and error_type == oerror_type,\ UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) +def first_error_only_line(compiler_output: list, errors: list): + line, column, error_type, _ = parse_error(errors[0]) + + oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) + + assert line == oline and error_type == oerror_type,\ + UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) + + +def get_file_name(path: str): + try: + return path[path.rindex('/') + 1:] + except ValueError: + return path def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): try: sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() - except TimeoutError: + except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT + assert return_code == 1, TEST_MUST_FAIL % get_file_name(cool_file_path) + + fd = open(error_file_path, 'r') + errors = fd.read().split('\n') + fd.close() + + # checking the errors of compiler compiler_output = output.split('\n') + cmp(compiler_output[2:], errors) - if error_file_path: - assert return_code == 1, TEST_MUST_FAIL % cool_file_path +SPIM_HEADER = r'''^SPIM Version .+ of .+ +Copyright .+\, James R\. Larus\. +All Rights Reserved\. +See the file README for a full copyright notice\. +(?:Loaded: .+\n)*''' +def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): + try: + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) + except subprocess.TimeoutExpired: + assert False, COMPILER_TIMEOUT + + spim_file = cool_file_path[:-2] + 'mips' - fd = open(error_file_path, 'r') - errors = fd.read().split('\n') + try: + fd = open(input_file_path, 'rb') + sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), capture_output=True, timeout=timeout) fd.close() + mo = re.match(SPIM_HEADER, sp.stdout.decode()) + if mo: + output = mo.string[mo.end():] + except subprocess.TimeoutExpired: + assert False, SPIM_TIMEOUT + + fd = open(output_file_path, 'r') + eoutput = fd.read() + fd.close() - # checking the errors of compiler - cmp(compiler_output[2:], errors) - else: - print(return_code, output) - assert return_code == 0, TEST_MUST_COMPILE % cool_file_path \ No newline at end of file + assert output == eoutput, UNEXPECTED_OUTPUT % (spim_file, repr(output), repr(eoutput))