|
| 1 | +import { Frame } from "./environment"; |
| 2 | +import { Method } from "../types/methods"; |
| 3 | +import { Node } from "../../ast/types/ast"; |
| 4 | +import { String } from "../types/nonPrimitives"; |
| 5 | +import { Type } from "../types/type"; |
1 | 6 | import { |
2 | 7 | BadOperandTypesError, |
3 | 8 | IncompatibleTypesError, |
4 | | - MethodCannotBeAppliedError, |
| 9 | + VariableAlreadyDefinedError, |
5 | 10 | } from "../errors"; |
6 | | -import { Frame, VariableAlreadyDefinedError } from "./environment"; |
7 | | -import { Node } from "../../ast/types/ast"; |
8 | | -import { String } from "../types/nonPrimitives"; |
9 | | -import { ClassMethod, Parameter, Type } from "../types/type"; |
| 11 | +import { |
| 12 | + createArgumentList, |
| 13 | + createMethod, |
| 14 | + createMethodSignature, |
| 15 | +} from "../typeFactories/methodFactory"; |
10 | 16 | import { |
11 | 17 | Expression, |
12 | 18 | ExpressionName, |
@@ -51,6 +57,7 @@ export const check = ( |
51 | 57 | throw new Error( |
52 | 58 | "Right side of assignment statment should return a type." |
53 | 59 | ); |
| 60 | + console.log(node.left, leftType, node.right, currentType); |
54 | 61 | if (!leftType.canBeAssigned(currentType)) |
55 | 62 | return newResult(null, [new IncompatibleTypesError()]); |
56 | 63 | return OK_RESULT; |
@@ -284,61 +291,85 @@ export const check = ( |
284 | 291 | }, OK_RESULT); |
285 | 292 | } |
286 | 293 | case "MethodInvocation": { |
| 294 | + const errors: Error[] = []; |
287 | 295 | const method = frame.getMethod(node.identifier); |
288 | 296 | if (method instanceof Error) return newResult(null, [method]); |
289 | | - if (method.parameters.length !== node.argumentList.length) |
290 | | - return newResult(null, [new MethodCannotBeAppliedError()]); |
291 | | - const errors: Error[] = []; |
292 | | - for (let i = 0; i < method.parameters.length; i++) { |
293 | | - const parameter = method.parameters[i]; |
294 | | - const argument = node.argumentList[i]; |
295 | | - const argumentCheck = check(argument, frame); |
296 | | - if (argumentCheck.errors.length > 0) { |
297 | | - errors.push(...argumentCheck.errors); |
| 297 | + const argumentTypes: Type[] = []; |
| 298 | + for (const argument of node.argumentList) { |
| 299 | + const argumentResult = check(argument, frame); |
| 300 | + if (argumentResult.errors.length > 0) { |
| 301 | + errors.push(...argumentResult.errors); |
298 | 302 | continue; |
299 | 303 | } |
300 | | - if (!argumentCheck.currentType) |
301 | | - throw new Error("Argument check should result in a type."); |
302 | | - if (!parameter.canBeAssigned(argumentCheck.currentType)) |
303 | | - errors.push(new IncompatibleTypesError()); |
| 304 | + if (!argumentResult.currentType) |
| 305 | + throw new Error("Arguments should have a type."); |
| 306 | + argumentTypes.push(argumentResult.currentType); |
304 | 307 | } |
305 | | - return newResult(method.returnType, errors); |
| 308 | + const argumentList = createArgumentList(...argumentTypes); |
| 309 | + if (argumentList instanceof Error) |
| 310 | + return newResult(null, [...errors, argumentList]); |
| 311 | + const returnType = method.invoke(argumentList); |
| 312 | + if (returnType instanceof Error) |
| 313 | + return newResult(null, [...errors, returnType]); |
| 314 | + return newResult(returnType, errors); |
306 | 315 | } |
307 | 316 | case "NormalClassDeclaration": { |
308 | 317 | const errors: Error[] = []; |
309 | 318 | const classFrame = frame.newChildFrame(); |
| 319 | + const furtherChecks: (() => void)[] = []; |
310 | 320 | node.classBody.forEach((bodyDeclaration) => { |
311 | 321 | if (bodyDeclaration.kind === "MethodDeclaration") { |
312 | | - const method = new ClassMethod(); |
313 | | - method.modifiers = bodyDeclaration.methodModifier; |
314 | | - const returnType = frame.getType(bodyDeclaration.methodHeader.result); |
315 | | - if (returnType instanceof Error) { |
316 | | - errors.push(returnType); |
317 | | - return; |
318 | | - } |
319 | | - method.returnType = returnType; |
320 | | - const parameters: Parameter[] = []; |
321 | | - bodyDeclaration.methodHeader.formalParameterList.forEach( |
322 | | - (parameter) => { |
323 | | - const type = classFrame.getType(parameter.unannType); |
324 | | - if (type instanceof Type) { |
325 | | - const param = new Parameter(); |
326 | | - param.name = parameter.identifier; |
327 | | - param.type = type; |
328 | | - parameters.push(param); |
329 | | - } |
| 322 | + const methodName = bodyDeclaration.methodHeader.identifier; |
| 323 | + if (classFrame.isMethodInFrame(methodName)) { |
| 324 | + const method = classFrame.getMethod(methodName) as Method; |
| 325 | + const overloadSignature = createMethodSignature( |
| 326 | + classFrame, |
| 327 | + bodyDeclaration |
| 328 | + ); |
| 329 | + if (overloadSignature instanceof Error) { |
| 330 | + errors.push(overloadSignature); |
| 331 | + return; |
330 | 332 | } |
331 | | - ); |
332 | | - method.parameters = parameters; |
333 | | - classFrame.setMethod(bodyDeclaration.methodHeader.identifier, method); |
334 | | - } |
335 | | - }); |
336 | | - node.classBody.forEach((bodyDeclaration) => { |
337 | | - if (bodyDeclaration.kind === "MethodDeclaration") { |
338 | | - const checkResult = check(bodyDeclaration.methodBody, classFrame); |
339 | | - errors.push(...checkResult.errors); |
| 333 | + const error = method.addOverload(overloadSignature); |
| 334 | + if (error) errors.push(error); |
| 335 | + furtherChecks.push(() => { |
| 336 | + const methodFrame = classFrame.newChildFrame(); |
| 337 | + overloadSignature.mapParameters((name, type) => { |
| 338 | + const error = methodFrame.setVariable(name, type); |
| 339 | + if (error) errors.push(error); |
| 340 | + }); |
| 341 | + methodFrame.setReturnType(overloadSignature.getReturnType()); |
| 342 | + const checkResult = check( |
| 343 | + bodyDeclaration.methodBody, |
| 344 | + methodFrame |
| 345 | + ); |
| 346 | + errors.push(...checkResult.errors); |
| 347 | + }); |
| 348 | + } else { |
| 349 | + const method = createMethod(frame, bodyDeclaration); |
| 350 | + if (method instanceof Error) { |
| 351 | + errors.push(method); |
| 352 | + return; |
| 353 | + } |
| 354 | + classFrame.setMethod(methodName, method); |
| 355 | + furtherChecks.push(() => { |
| 356 | + const methodFrame = classFrame.newChildFrame(); |
| 357 | + const methodSignature = method.getOverload(0); |
| 358 | + methodSignature.mapParameters((name, type) => { |
| 359 | + const error = methodFrame.setVariable(name, type); |
| 360 | + if (error) errors.push(error); |
| 361 | + }); |
| 362 | + methodFrame.setReturnType(methodSignature.getReturnType()); |
| 363 | + const checkResult = check( |
| 364 | + bodyDeclaration.methodBody, |
| 365 | + methodFrame |
| 366 | + ); |
| 367 | + errors.push(...checkResult.errors); |
| 368 | + }); |
| 369 | + } |
340 | 370 | } |
341 | 371 | }); |
| 372 | + furtherChecks.forEach((furtherCheck) => furtherCheck()); |
342 | 373 | return newResult(null, errors); |
343 | 374 | } |
344 | 375 | case "PostfixExpression": { |
@@ -392,6 +423,17 @@ export const check = ( |
392 | 423 | ); |
393 | 424 | } |
394 | 425 | } |
| 426 | + case "ReturnStatement": { |
| 427 | + const expressionCheck = check(node.exp, frame); |
| 428 | + if (expressionCheck.errors.length > 0) return expressionCheck; |
| 429 | + if (!expressionCheck.currentType) |
| 430 | + throw new Error("Expression check should return a type."); |
| 431 | + const returnType = frame.getReturn(); |
| 432 | + if (returnType instanceof Error) return newResult(null, [returnType]); |
| 433 | + if (!returnType.canBeAssigned(expressionCheck.currentType)) |
| 434 | + return newResult(null, [new IncompatibleTypesError()]); |
| 435 | + return OK_RESULT; |
| 436 | + } |
395 | 437 | case "TernaryExpression": { |
396 | 438 | const conditionCheck = check(node.condition, frame); |
397 | 439 | if (conditionCheck.errors.length > 0) return conditionCheck; |
@@ -432,7 +474,6 @@ export const check = ( |
432 | 474 | return OK_RESULT; |
433 | 475 | } |
434 | 476 | default: |
435 | | - console.log(node); |
436 | 477 | throw new Error( |
437 | 478 | `Check is not implemented for this type of node ${node.kind}.` |
438 | 479 | ); |
|
0 commit comments