PageRenderTime 71ms CodeModel.GetById 37ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/LispMacro.cpp

https://bitbucket.org/hardtack/resoup
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}