/LispMacro.cpp
C++ | 482 lines | 445 code | 27 blank | 10 comment | 90 complexity | 452386912c10eeedc4e2cddfe0baeb86 MD5 | raw file
1/* 2 * LispMacro.cpp 3 * resoup 4 * 5 * Created by ??? on 10. 9. 2.. 6 * Copyright 2010 Unplug. All rights reserved. 7 * 8 */ 9 10#include "LispMacro.h" 11#include "LispQuote.h" 12#include "Evaluator.h" 13#include "LispBoolean.h" 14#include "LispString.h" 15#include <iostream> 16#include "Functions.h" 17 18using namespace Functions; 19using namespace Evaluator; 20 21int LispMacro::getClassIdentifier(){ 22 return LISPMACRO; 23} 24 25LispObject* DefineMacro::copy(){ 26 return new DefineMacro(*this); 27} 28 29LispObject* DefineMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (DefineNotAllowed &, 30 NumberOfArgumentsDoesNotMatchException &, 31 TypeOfArgumentDoesNotMatchException &, 32 Exception &){ 33 if (argsSize != 2){ 34 DefineNotAllowed e; 35 e.syntaxError = true; 36 throw e; 37 } else if (args[0]->getClassIdentifier() == LISPSYMBOL) { 38 LispObject *evaluated = evaluate(args[1], env); 39 if(evaluated->getClassIdentifier() == LISPMACRO){ 40 delete evaluated; 41 DefineNotAllowed e; 42 e.syntaxError = true; 43 throw e; 44 } 45 LispSymbolValuePair *svp = new LispSymbolValuePair(((LispSymbol *)args[0])->getName(), evaluated); 46 env->addSymbolValuePair(svp); 47 } else if (args[0]->getClassIdentifier() == LISPLIST) { 48 // Change to lambda 49 LispList *list = (LispList *)args[0]; 50 // Syntax check 51 if (list->getSize() == 0) { 52 DefineNotAllowed e; 53 e.syntaxError = true; 54 throw e; 55 } 56 for (int i = 0; i < list->getSize(); i++) { 57 LispObject *element = list->getElement(i); 58 if (element->getClassIdentifier() != LISPSYMBOL) { 59 DefineNotAllowed e; 60 e.syntaxError = true; 61 throw e; 62 } 63 delete element; 64 } 65 LispSymbol *name = (LispSymbol *)list->getElement(0); 66 LispList *argList = new LispList(); 67 for (int i = 1; i < list->getSize(); i++) { 68 LispSymbol *arg = (LispSymbol *)list->getElement(i); 69 argList->addElement(arg); 70 delete arg; 71 } 72 LispList *lambdaList = new LispList(); 73 LambdaMacro *lambda = new LambdaMacro(); 74 lambdaList->addElement(lambda); 75 delete lambda; 76 lambdaList->addElement(argList); 77 delete argList; 78 lambdaList->addElement(args[1]); 79 env->addSymbolValuePair(new LispSymbolValuePair(name->getName(), evaluate(lambdaList, env))); 80 delete lambdaList; 81 } else { 82 DefineNotAllowed e; 83 e.syntaxError = true; 84 throw e; 85 } 86 return new LispNil(); 87} 88 89 90LispObject* LambdaMacro::copy(){ 91 return new LambdaMacro(*this); 92} 93 94LispObject* LambdaMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, TypeOfArgumentDoesNotMatchException &, Exception &){ 95 char *name = stringcpy("lambda"); 96 if(argsSize != 2){ 97 NumberOfArgumentsDoesNotMatchException e; 98 e.has = argsSize; 99 e.required = 2; 100 e.maxRequired = 2; 101 e.name = stringcpy(name); 102 throw e; 103 } 104 LispObject *first = args[0]; 105 LispObject *second = args[1]; 106 107 if (first->getClassIdentifier() != LISPLIST) { 108 TypeOfArgumentDoesNotMatchException e; 109 e.has = first->getClassIdentifier(); 110 e.required = LISPLIST; 111 e.at = 1; 112 e.name = stringcpy(name); 113 throw e; 114 } 115 switch (first->getClassIdentifier()) { 116 case LISPLIST:{ 117 LispList *list = (LispList *)first; 118 for (int i = 0; i < list->getSize(); i++) { 119 LispObject *element = list->getElement(i); 120 int ci = element->getClassIdentifier(); 121 delete element; 122 if (ci != LISPSYMBOL) { 123 TypeOfArgumentDoesNotMatchException e; 124 e.has = ci; 125 e.required = LISPSYMBOL; 126 e.at = i + 1; 127 e.name = stringcpy(name); 128 throw e; 129 } 130 } 131 LispProcedure *procedure = new LispProcedure(list->getSize(), list->getSize(), (LispList *)second, env); 132 for (int i = 0; i < list->getSize(); i++) { 133 LispSymbol *element = (LispSymbol *)list->getElement(i); 134 procedure->addNameOfArgument(element->getName()); 135 delete element; 136 } 137 return procedure; 138 } 139 default:{ 140 if (second->getClassIdentifier() != LISPLIST) { 141 TypeOfArgumentDoesNotMatchException e; 142 e.has = second->getClassIdentifier(); 143 e.required = LISPLIST; 144 e.at = 2; 145 e.name = stringcpy(name); 146 throw e; 147 } 148 return new LispProcedure(0 , 0, (LispList *)second, env); 149 } 150 } 151} 152 153 154LispObject* CondMacro::copy(){ 155 return new CondMacro(*this); 156} 157 158LispObject* CondMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, TypeOfArgumentDoesNotMatchException &, Exception &){ 159 for (int i = 0; i < argsSize; i++) { 160 if (args[i]->getClassIdentifier() != LISPLIST) { 161 TypeOfArgumentDoesNotMatchException e; 162 e.at = i + 1; 163 e.has = args[i]->getClassIdentifier(); 164 e.required = LISPLIST; 165 e.name = stringcpy("cond"); 166 throw e; 167 } else if (((LispList *)args[i])->getSize() != 2) { 168 NumberOfArgumentsDoesNotMatchException e; 169 e.has = ((LispList *)args[i])->getSize(); 170 e.required = 2; 171 e.maxRequired = 2; 172 e.name = stringcpy("name"); 173 throw e; 174 } 175 } 176 return evaluate(condToIf(0, (LispList **)args, argsSize), env); 177} 178 179LispList* CondMacro::condToIf(int i, LispList **args, int argsSize){ 180 if(i == argsSize - 1){ 181 LispList *ifList = new LispList(); 182 IfMacro *ifmacro = new IfMacro(); 183 ifList->addElement(ifmacro); 184 delete ifmacro; 185 LispObject *boolean = args[i]->getElement(0); 186 ifList->addElement(boolean); 187 delete boolean; 188 LispObject *first = args[i]->getElement(1); 189 ifList->addElement(first); 190 delete first; 191 LispNil *nil = new LispNil(); 192 ifList->addElement(nil); 193 delete nil; 194 return ifList; 195 }else { 196 LispList *ifList = new LispList(); 197 IfMacro *ifmacro = new IfMacro(); 198 ifList->addElement(ifmacro); 199 delete ifmacro; 200 LispObject *boolean = args[i]->getElement(0); 201 ifList->addElement(boolean); 202 delete boolean; 203 LispObject *first = args[i]->getElement(1); 204 ifList->addElement(first); 205 delete first; 206 ifList->addElement(condToIf(i + 1, args, argsSize)); 207 return ifList; 208 } 209 210} 211 212LispObject* IfMacro::copy(){ 213 return new IfMacro(*this); 214} 215 216LispObject* IfMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, Exception &){ 217 if (argsSize != 3) { 218 NumberOfArgumentsDoesNotMatchException e; 219 e.has = argsSize; 220 e.maxRequired = 3; 221 e.required = 3; 222 e.name = stringcpy("if"); 223 throw e; 224 } 225 bool boolean; 226 LispObject *boolObj = evaluate(args[0], env); 227 int ci = boolObj->getClassIdentifier(); 228 if (ci == LISPBOOLEAN) { 229 boolean = ((LispBoolean *) boolObj)->getBool(); 230 } else if (ci == LISPNIL){ 231 boolean = false; 232 } else { 233 boolean = true; 234 } 235 if (boolean) { 236 return evaluate(args[1], env); 237 } 238 else { 239 return evaluate(args[2], env); 240 } 241} 242 243 244LispObject* QuoteMacro::copy(){ 245 return new QuoteMacro(*this); 246} 247 248LispObject* QuoteMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, Exception &){ 249 if (argsSize != 1) { 250 NumberOfArgumentsDoesNotMatchException e; 251 e.has = argsSize; 252 e.maxRequired = 1; 253 e.required = 1; 254 e.name = stringcpy("quote"); 255 throw e; 256 } 257 return ((LispQuote *)args[0])->getItem(); 258} 259 260LispObject* BeginMacro::copy(){ 261 return new BeginMacro(*this); 262} 263LispObject* BeginMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, Exception &){ 264 if (argsSize == 0){ 265 NumberOfArgumentsDoesNotMatchException e; 266 e.has = 0; 267 e.name = stringcpy("begin"); 268 e.required = 1; 269 e.maxRequired = UNLIMITED_ARGUMENTS; 270 throw e; 271 } 272 for (int i = 0; i < argsSize - 1; i++) { 273 evaluate(args[i], env); 274 } 275 return evaluate(args[argsSize - 1], env); 276} 277 278LispObject* LetMacro::copy(){ 279 return new LetMacro(*this); 280} 281 282LispObject* LetMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, TypeOfArgumentDoesNotMatchException &, Exception &){ 283 char *name = stringcpy("let"); 284 if (argsSize != 2){ 285 NumberOfArgumentsDoesNotMatchException e; 286 e.has = argsSize; 287 e.required = 2; 288 e.maxRequired = 2; 289 e.name = name; 290 throw e; 291 } 292 293 if (args[0]->getClassIdentifier() != LISPLIST){ 294 TypeOfArgumentDoesNotMatchException e; 295 e.at = 0 + 1; 296 e.has = args[0]->getClassIdentifier(); 297 e.required = LISPLIST; 298 e.name = name; 299 throw e; 300 } 301 int itemSize = ((LispList *)args[0])->getSize(); 302 LispObject **items = new LispObject*[itemSize]; 303 LispEnvironment *newEnv = new LispEnvironment(env); 304 for (int i = 0; i < itemSize; i++) { 305 items[i] = ((LispList *)args[0])->getElement(i); 306 if (items[i]->getClassIdentifier() != LISPLIST) { 307 TypeOfArgumentDoesNotMatchException e; 308 e.has = items[i]->getClassIdentifier(); 309 for (int j = 0; j < i + 1; j++) { 310 delete items[j]; 311 } 312 delete[] items; 313 e.required = LISPLIST; 314 e.name = stringcpy("List"); 315 e.at = i; 316 throw e; 317 } 318 if (((LispList *)items[i])->getSize() != 2) { 319 NumberOfArgumentsDoesNotMatchException e; 320 e.has = ((LispList *)items[i])->getSize(); 321 for (int j = 0; j < i + 1; j++) { 322 delete items[j]; 323 } 324 delete[] items; 325 e.required = 2; 326 e.maxRequired = 2; 327 e.name = stringcpy("List"); 328 throw e; 329 } 330 LispObject *symbol = ((LispList *)items[i])->getElement(0); 331 if (symbol->getClassIdentifier() != LISPSYMBOL) { 332 TypeOfArgumentDoesNotMatchException e; 333 e.has = items[i]->getClassIdentifier(); 334 for (int j = 0; j < i + 1; j++) { 335 delete items[j]; 336 } 337 delete[] items; 338 e.required = LISPSYMBOL; 339 e.name = stringcpy("List"); 340 e.at = 0; 341 throw e; 342 } 343 LispObject *item = evaluate(((LispList *)items[i])->getElement(1), env); 344 newEnv->addSymbolValuePair(new LispSymbolValuePair(((LispSymbol *)symbol)->getName(), item)); 345 } 346 return evaluate(args[1], newEnv); 347} 348 349LispObject* LetAsteriskMacro::copy(){ 350 return new LetAsteriskMacro(*this); 351} 352LispObject* LetAsteriskMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, TypeOfArgumentDoesNotMatchException &, Exception &){ 353 char *name = stringcpy("let"); 354 if (argsSize != 2){ 355 NumberOfArgumentsDoesNotMatchException e; 356 e.has = argsSize; 357 e.required = 2; 358 e.maxRequired = 2; 359 e.name = name; 360 throw e; 361 } 362 363 if (args[0]->getClassIdentifier() != LISPLIST){ 364 TypeOfArgumentDoesNotMatchException e; 365 e.at = 0 + 1; 366 e.has = args[0]->getClassIdentifier(); 367 e.required = LISPLIST; 368 e.name = name; 369 throw e; 370 } 371 int itemSize = ((LispList *)args[0])->getSize(); 372 LispObject **items = new LispObject*[itemSize]; 373 LispEnvironment *newEnv = new LispEnvironment(env); 374 for (int i = 0; i < itemSize; i++) { 375 items[i] = ((LispList *)args[0])->getElement(i); 376 if (items[i]->getClassIdentifier() != LISPLIST) { 377 TypeOfArgumentDoesNotMatchException e; 378 e.has = items[i]->getClassIdentifier(); 379 for (int j = 0; j < i + 1; j++) { 380 delete items[j]; 381 } 382 delete[] items; 383 e.required = LISPLIST; 384 e.name = stringcpy("List"); 385 e.at = i; 386 throw e; 387 } 388 if (((LispList *)items[i])->getSize() != 2) { 389 NumberOfArgumentsDoesNotMatchException e; 390 e.has = ((LispList *)items[i])->getSize(); 391 for (int j = 0; j < i + 1; j++) { 392 delete items[j]; 393 } 394 delete[] items; 395 e.required = 2; 396 e.maxRequired = 2; 397 e.name = stringcpy("List"); 398 throw e; 399 } 400 LispObject *symbol = ((LispList *)items[i])->getElement(0); 401 if (symbol->getClassIdentifier() != LISPSYMBOL) { 402 TypeOfArgumentDoesNotMatchException e; 403 e.has = items[i]->getClassIdentifier(); 404 for (int j = 0; j < i + 1; j++) { 405 delete items[j]; 406 } 407 delete[] items; 408 e.required = LISPSYMBOL; 409 e.name = stringcpy("List"); 410 e.at = 0; 411 throw e; 412 } 413 LispObject *item = evaluate(((LispList *)items[i])->getElement(1), newEnv); 414 newEnv->addSymbolValuePair(new LispSymbolValuePair(((LispSymbol *)symbol)->getName(), item)); 415 } 416 return evaluate(args[1], newEnv); 417} 418 419LispObject* SetExcalMacro::copy(){ 420 return new SetExcalMacro(*this); 421} 422 423LispObject* SetExcalMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, 424 TypeOfArgumentDoesNotMatchException &, 425 DefineNotAllowed &, 426 Exception &){ 427 if (argsSize != 2) { 428 NumberOfArgumentsDoesNotMatchException e; 429 e.has = argsSize; 430 e.required = 2; 431 e.maxRequired = 2; 432 e.name = stringcpy("set!"); 433 throw e; 434 } 435 if (args[0]->getClassIdentifier() != LISPSYMBOL) { 436 TypeOfArgumentDoesNotMatchException e; 437 e.has = args[0]->getClassIdentifier(); 438 e.required = LISPSYMBOL; 439 e.name = stringcpy("set!"); 440 e.at = 1; 441 throw e; 442 } 443 LispSymbolValuePair **ptrSvp = env->getSymbolValuePairDoublePointer(((LispSymbol *)args[0])->getName()); 444 LispSymbolValuePair *tmp = *ptrSvp; 445 LispObject* evaluated = evaluate(args[1], env); 446 if (evaluated->getClassIdentifier() == LISPMACRO){ 447 delete evaluated; 448 DefineNotAllowed e; 449 e.syntaxError = true; 450 throw e; 451 } 452 *ptrSvp = new LispSymbolValuePair(((LispSymbol *)args[0])->getName(), evaluated); 453 delete tmp; 454 return new LispNil(); 455} 456LispObject* LoadMacro::copy(){ 457 return new LoadMacro(*this); 458} 459LispObject* LoadMacro::callMacro(LispObject **args, int argsSize, LispEnvironment *env) throw (NumberOfArgumentsDoesNotMatchException &, TypeOfArgumentDoesNotMatchException &, Exception &){ 460 if (argsSize != 1) { 461 NumberOfArgumentsDoesNotMatchException e; 462 e.has = argsSize; 463 e.required = 1; 464 e.maxRequired = 1; 465 e.name = stringcpy("load"); 466 throw e; 467 } 468 if (args[0]->getClassIdentifier() != LISPSTRING) { 469 TypeOfArgumentDoesNotMatchException e; 470 e.has = args[0]->getClassIdentifier(); 471 e.name = stringcpy("load"); 472 e.required = LISPSTRING; 473 e.at = 1; 474 throw e; 475 } 476 char *expression = loadFile(((LispString *)args[0])->getString()); 477 if(!run(expression, env)){ 478 std::cout << "Exit by external file" << std::endl; 479 exit(0); 480 } 481 return new LispNil(); 482}