Mercurial > lcfOS
changeset 167:0b5b2ee6b435
Added 2 unit tests
author | Windel Bouwman |
---|---|
date | Fri, 22 Mar 2013 17:40:13 +0100 |
parents | da0087b82fbe |
children | 49f1ab80d040 |
files | python/c3/analyse.py python/c3/astnodes.py python/c3/builder.py python/c3/codegenerator.py python/c3/parser.py python/c3/semantics.py python/c3/typecheck.py python/c3/visitor.py python/codeedit.py python/ide.py python/ppci/errors.py python/testc3.py |
diffstat | 12 files changed, 99 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/python/c3/analyse.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/analyse.py Fri Mar 22 17:40:13 2013 +0100 @@ -24,10 +24,13 @@ def analyze(self, sym): if type(sym) in [Variable, Constant]: sym.typ = self.resolveDesignator(sym.typ, sym) + elif type(sym) is Function: + pass elif type(sym) is VariableUse: sym.target = self.resolveDesignator(sym.target, sym) - elif type(sym) is ProcedureCall: + elif type(sym) is FunctionCall: sym.proc = self.resolveDesignator(sym.proc, sym) elif type(sym) is FunctionType: sym.returntype = self.resolveDesignator(sym.returntype) + sym.parametertypes = [self.resolveDesignator(pt) for pt in sym.parametertypes]
--- a/python/c3/astnodes.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/astnodes.py Fri Mar 22 17:40:13 2013 +0100 @@ -26,11 +26,11 @@ return '{0}'.format(self.name) class FunctionType(Type): - def __init__(self, parameters, returntype): - self.parameters = parameters + def __init__(self, parametertypes, returntype): + self.parametertypes = parametertypes self.returntype = returntype def __repr__(self): - params = ','.join([str(v) for v in self.parameters]) + params = ', '.join([str(v) for v in self.parametertypes]) return '{1} f({0})'.format(params, self.returntype) class DefinedType(Type): @@ -140,7 +140,7 @@ def __repr__(self): return 'ASSIGNMENT' -class ProcedureCall(Node): +class FunctionCall(Node): def __init__(self, proc, args): self.proc = proc self.args = args
--- a/python/c3/builder.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/builder.py Fri Mar 22 17:40:13 2013 +0100 @@ -12,19 +12,9 @@ def build(self, src): # Store src for later: self.src = src - print('[0] source:') - print(src) - print('[1] parsing') self.pkg = self.p.parseSource(src) self.al.analyzePackage(self.pkg) self.tc.checkPackage(self.pkg) - print('{0} errors'.format(len(self.diag.diags))) - for d in self.diag.diags: - print('ERROR:') - ppci.printError(src, d) - print('[2] ast:') - self.ap.printAst(self.pkg) - ok = len(self.diag.diags) == 0 if ok: print('Generating ir-code')
--- a/python/c3/codegenerator.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/codegenerator.py Fri Mar 22 17:40:13 2013 +0100 @@ -36,12 +36,12 @@ elif type(code) is astnodes.IfStatement: genExprCode(bb, code.condition) # TODO: implement IF. - t1, t2 = 1,2 + t1, t2 = 1, 2 b = ir.BranchInstruction(t1, t2) bb.Instructions.append(b) genCode(bb, code.truestatement) genCode(bb, code.falsestatement) - elif type(code) is astnodes.ProcedureCall: + elif type(code) is astnodes.FunctionCall: ins = ir.CallInstruction('f', []) bb.Instructions.append(ins) elif type(code) is astnodes.EmptyStatement:
--- a/python/c3/parser.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/parser.py Fri Mar 22 17:40:13 2013 +0100 @@ -139,7 +139,7 @@ self.Consume(';') return self.sema.actOnAssignment(lval, rval, loc) - def parseProcedureCall(self, procedure): + def parseProcedureCall(self, func): self.Consume('(') args = [] if not self.hasConsumed(')'): @@ -147,7 +147,7 @@ while self.hasConsumed(','): args.append(self.parseExpression()) self.Consume(')') - return astnodes.ProcedureCall(procedure, args) + return self.sema.actOnFunctionCall(func, args, func.loc) def parseIfStatement(self): loc = self.Consume('if').loc
--- a/python/c3/semantics.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/semantics.py Fri Mar 22 17:40:13 2013 +0100 @@ -36,7 +36,8 @@ return p def actOnFuncDef2(self, parameters, returntype, body): self.curFunc.body = body - self.curFunc.typ = astnodes.FunctionType(parameters, returntype) + paramtypes = [p.typ for p in parameters] + self.curFunc.typ = astnodes.FunctionType(paramtypes, returntype) self.curFunc = None self.curScope = self.curScope.parent def actOnType(self, tok): @@ -63,6 +64,10 @@ a = astnodes.Assignment(lval, rval) a.loc = loc return a + def actOnFunctionCall(self, func, args, loc): + fc = astnodes.FunctionCall(func, args) + fc.loc = loc + return fc def actOnIfStatement(self, cond, yes, no, loc): i = astnodes.IfStatement(cond, yes, no) i.loc = loc
--- a/python/c3/typecheck.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/typecheck.py Fri Mar 22 17:40:13 2013 +0100 @@ -28,12 +28,22 @@ self.diag.error('Cannot assign {0} to {1}'.format(sym.rval.typ, sym.lval.typ), sym.loc) elif type(sym) is ReturnStatement: pass - elif type(sym) is ProcedureCall: - # Check arguments: + elif type(sym) is FunctionCall: if sym.proc: - pass - # determine return type: - sym.typ = sym.proc.typ.returntype + # Check arguments: + ngiv = len(sym.args) + ptypes = sym.proc.typ.parametertypes + nreq = len(ptypes) + if ngiv != nreq: + self.diag.error('Function {2}: {0} arguments required, {1} given'.format(nreq, ngiv, sym.proc.name), sym.loc) + else: + for a, at in zip(sym.args, ptypes): + if not equalTypes(a.typ, at): + self.diag.error('Got {0}, expected {1}'.format(a.typ, at), a.loc) + # determine return type: + sym.typ = sym.proc.typ.returntype + else: + sym.typ = intType elif type(sym) is VariableUse: if sym.target: sym.typ = sym.target.typ
--- a/python/c3/visitor.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/c3/visitor.py Fri Mar 22 17:40:13 2013 +0100 @@ -24,9 +24,9 @@ self.visit(node.condition) self.visit(node.truestatement) self.visit(node.falsestatement) - elif type(node) is ProcedureCall: - pass - # TODO + elif type(node) is FunctionCall: + for arg in node.args: + self.visit(arg) elif type(node) is Assignment: self.visit(node.lval) self.visit(node.rval)
--- a/python/codeedit.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/codeedit.py Fri Mar 22 17:40:13 2013 +0100 @@ -70,6 +70,7 @@ txt = '\n'.join(prevRows) c = clipVal(c, 1, len(self.getRow(r))) self.CursorPosition = len(txt) + c + 1 + self.showRow(self.CursorRow) def getRow(self, r): rows = self.Rows r = r - 1 @@ -149,11 +150,13 @@ painter.setPen(errorPen) x = self.xposTXT + (e.loc.col - 1) * chw - 2 wt = e.loc.length * chw + 4 - painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7) + dy = self.charDescent + painter.drawLine(x, ypos + dy, x + wt, ypos + dy) + #painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7) # print error balloon - painter.drawText(x, ypos + chh, e.msg) - if len(curErrors) > 0: - ypos += chh + #painter.drawText(x, ypos + chh, e.msg) + #if len(curErrors) > 0: + # ypos += chh ypos += chh def keyPressEvent(self, event): @@ -221,6 +224,8 @@ Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v)) def setErrors(self, el): self.ic.setErrors(el) + def setFocus(self): + self.ic.setFocus() if __name__ == '__main__': app = QApplication(sys.argv)
--- a/python/ide.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/ide.py Fri Mar 22 17:40:13 2013 +0100 @@ -26,7 +26,7 @@ self.setReadOnly(True) self.append('Build output will appear here!') -class BuildErrors(QListView): +class BuildErrors(QTreeView): sigErrorSelected = pyqtSignal(object) def __init__(self, parent=None): super(BuildErrors, self).__init__(parent) @@ -36,10 +36,15 @@ self.errorIcon = QIcon('error.png') def setErrorList(self, errorlist): model = QStandardItemModel() + model.setHorizontalHeaderLabels(['Message', 'Row', 'Column']) for e in errorlist: - item = QStandardItem(self.errorIcon, str(e)) + item = QStandardItem(self.errorIcon, str(e.msg)) item.setData(e) - model.appendRow(item) + irow = QStandardItem(str(e.loc.row)) + irow.setData(e) + icol = QStandardItem(str(e.loc.col)) + icol.setData(e) + model.appendRow([item, irow, icol]) self.setModel(model) def itemSelected(self, index): if not index.isValid(): @@ -331,20 +336,19 @@ if not ce: return ce.setRowCol(err.loc.row, err.loc.col) + ce.setFocus() # Project loading: # Build recepy: def buildFile(self): ce = self.activeMdiChild() - print('BUILD file') if ce: source = ce.Source self.buildOutput.clear() self.buildOutput.append('Starting build') ir = self.c3front.build(source) ast = self.c3front.pkg - print('setting ast', ast) self.astViewer.setAst(ast) self.buildOutput.append("Done!") def buildProject(self): @@ -360,7 +364,6 @@ self.buildOutput.append(str(err)) ce = self.activeMdiChild() if ce: - print('setting errors') ce.setErrors(self.diag.diags) self.buildOutput.append("Done!")
--- a/python/ppci/errors.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/ppci/errors.py Fri Mar 22 17:40:13 2013 +0100 @@ -8,7 +8,7 @@ self.msg = msg self.loc = loc def __repr__(self): - return 'Compilererror {0} at {1}'.format(self.msg, self.loc) + return 'Compilererror {0} at row {1}'.format(self.msg, self.loc.row) def printError(source, e): def printLine(row, txt): @@ -42,4 +42,6 @@ self.diags.append(d) def error(self, msg, loc): self.addDiag(CompilerError(msg, loc)) + def clear(self): + self.diags.clear()
--- a/python/testc3.py Fri Mar 22 16:15:31 2013 +0100 +++ b/python/testc3.py Fri Mar 22 17:40:13 2013 +0100 @@ -1,5 +1,6 @@ import c3 import time, ppci, x86, ir +import unittest testsrc = """package test; @@ -7,7 +8,7 @@ var double e; var int f; -const int A = 1337.; +const int A = 1337; function void test1() { @@ -34,7 +35,7 @@ { if (a > 0) { - a = 2 + t2(a - 1); + a = 2 + t2(a - 1, 1.0); } return a + b; @@ -77,5 +78,43 @@ diag = ppci.DiagnosticsManager() c3compile(testsrc, diag) -do() +class testA(unittest.TestCase): + def setUp(self): + self.diag = ppci.DiagnosticsManager() + self.builder = c3.Builder(self.diag) + def testFunctArgs(self): + snippet = """ + package testargs; + function void t2(int a, double b) + { + t2(2, 2); + t2(2); + t2(1, 1.2); + } + """ + self.diag.clear() + ir = self.builder.build(snippet) + print(self.diag.diags) + def testExpressions(self): + snippet = """ + package test; + function void t(int a, double b) + { + var int a2; + var bool c; + + a2 = b * a; + c = a; + c = b > 1; + } + """ + self.diag.clear() + ir = self.builder.build(snippet) + print(self.diag.diags) + +if __name__ == '__main__': + do() + unittest.main() + +