├── Benchmark ├── GNUmakefile ├── compile.sh ├── fib.st ├── main.m ├── prototype.st └── test.st ├── Compiler ├── COPYING ├── GNUmakefile ├── HACKING ├── Native │ ├── GNUmakefile │ ├── test.st │ └── tst.m ├── README ├── edlc.1 ├── examples │ ├── 1log.st │ ├── ObjectMixer │ │ └── ObjectMixer.st │ ├── a.st │ ├── addMethod.st │ ├── appkit.st │ ├── array.st │ ├── b.st │ ├── bench.st │ ├── block.st │ ├── cat.st │ ├── cat2.st │ ├── dispatch.st │ ├── dispatch_locked.st │ ├── empty.st │ ├── enum.st │ ├── eric.st │ ├── fib.st │ ├── fib2.st │ ├── float.st │ ├── foo.st │ ├── gt.st │ ├── if.st │ ├── int.st │ ├── ivar.st │ ├── localblock.st │ ├── ls.st │ ├── mapReduce.st │ ├── mult.st │ ├── nico.st │ ├── nsrange.st │ ├── null.st │ ├── overflow.st │ ├── retainblock.st │ ├── script.st │ ├── self.st │ ├── serial.st │ ├── shell.st │ ├── simpleblock.st │ ├── str.st │ ├── subclass.st │ ├── sym.st │ ├── t1.st │ ├── t2.st │ └── test.st ├── main.m ├── old │ ├── ExecutionContext.h │ ├── ExecutionContext.m │ ├── NSObject+ReplaceMethods.h │ ├── NSObject+ReplaceMethods.m │ ├── README │ ├── StringMap.h │ ├── StringMap.m │ ├── main.m │ ├── parser.h │ ├── smalltalk.l │ └── smalltalk.yacc └── test.st ├── EScript ├── COPYING ├── EScriptCompiler.h ├── EScriptCompiler.m ├── EScriptObject.h ├── EScriptObject.m ├── EScriptParser.h ├── EScriptParser.m ├── EScriptPreamble.h ├── EScriptPreamble.m ├── EScriptTransform.h ├── EScriptTransform.m ├── GNUmakefile ├── README ├── escript.y ├── lemon.c ├── lempar.c └── test.escript ├── GNUmakefile ├── LKPlugins ├── CommentsToLogs │ ├── GNUmakefile │ └── transform.m ├── GNUmakefile ├── LowerIfResponds │ ├── GNUmakefile │ └── transform.m └── LowerIfTrue │ ├── GNUmakefile │ └── transform.m ├── LanguageKit ├── COPYING ├── CodeGen │ ├── ABI.h │ ├── ABIInfo.h │ ├── AMD64 │ │ ├── AMD64ABIInfo.h │ │ └── AMD64ABIInfo.mm │ ├── CGObjCGNU.mm │ ├── CGObjCRuntime.h │ ├── CodeGenAssignments.h │ ├── CodeGenAssignments.mm │ ├── CodeGenBlock.h │ ├── CodeGenBlock.mm │ ├── CodeGenHelpers.mm │ ├── CodeGenLexicalScope.h │ ├── CodeGenLexicalScope.mm │ ├── CodeGenModule.h │ ├── CodeGenModule.mm │ ├── CodeGenTypes.h │ ├── CodeGenTypes.mm │ ├── GNUmakefile │ ├── GenericABIInfo.h │ ├── GenericABIInfo.mm │ ├── LKCompiler+JTL.mm │ ├── LLVMCodeGen.h │ ├── LLVMCodeGen.mm │ ├── LLVMCompat.h │ ├── ObjCXXRuntime.h │ ├── UglyGNUHack.h │ ├── UnboxPass.cpp │ ├── objc_pointers.h │ └── unistd.h ├── GNUmakefile ├── LKAST.h ├── LKAST.m ├── LKASTVisitor.h ├── LKASTVisitor.m ├── LKArrayExpr.h ├── LKArrayExpr.m ├── LKAssignExpr.h ├── LKAssignExpr.m ├── LKAutoBoxFixup.m ├── LKBlockExpr.h ├── LKBlockExpr.m ├── LKCategory.h ├── LKCategory.m ├── LKCodeGen.h ├── LKCodeGen.m ├── LKComment.h ├── LKComment.m ├── LKComparison.h ├── LKComparison.m ├── LKCompiler.h ├── LKCompiler.m ├── LKCompilerErrors.h ├── LKCompilerErrors.m ├── LKDeclRef.h ├── LKDeclRef.m ├── LKEnumReference.h ├── LKEnumReference.m ├── LKFunction.h ├── LKFunction.m ├── LKFunctionCall.h ├── LKFunctionCall.m ├── LKIfStatement.h ├── LKIfStatement.m ├── LKInterpreter.h ├── LKInterpreter.m ├── LKInterpreterRuntime.h ├── LKInterpreterRuntime.m ├── LKLiteral.h ├── LKLiteral.m ├── LKLoop.h ├── LKLoop.m ├── LKMessageSend.h ├── LKMessageSend.m ├── LKMethod.h ├── LKMethod.m ├── LKModule.h ├── LKModule.m ├── LKReturn.h ├── LKReturn.m ├── LKSubclass.h ├── LKSubclass.m ├── LKSymbolRef.h ├── LKSymbolRef.m ├── LKSymbolTable.h ├── LKSymbolTable.m ├── LKToken.h ├── LKToken.m ├── LKTypeHelpers.h ├── LKTypeHelpers.m ├── LKVariableDecl.h ├── LKVariableDecl.m ├── LanguageKit.h ├── LanguageKit.xcodeproj │ └── project.pbxproj ├── ObjCConstants.plist ├── README └── Runtime │ ├── BigInt.h │ ├── BigInt.m │ ├── BlockClosure+debug.m │ ├── BlockClosure.h │ ├── BlockClosure.m │ ├── BlockContext.h │ ├── BoxedFloat.h │ ├── BoxedFloat.m │ ├── GNUmakefile │ ├── LKObject.h │ ├── LanguageKitExceptions.m │ ├── MsgSendSmallInt.m │ ├── NSString+conversions.m │ ├── NSValue+structs.m │ ├── OverflowHandler.m │ ├── Symbol.h │ ├── Symbol.m │ ├── dwarf_eh.h │ └── unwind.h └── Smalltalk ├── COPYING ├── GNUmakefile ├── README ├── SmalltalkCompiler.h ├── SmalltalkCompiler.m ├── SmalltalkParser.h ├── SmalltalkParser.m ├── Support ├── BlockClosure.m ├── GNUmakefile ├── NSArray+map.h ├── NSArray+map.m ├── NSObject+log.m ├── NSObject+yourself.m ├── NSString+casting.m ├── NSString+comma.m └── NSValue+structs.m ├── Tests ├── InFutureTestBoxing │ ├── expected.txt │ └── test.st ├── README ├── Template │ ├── expected.txt │ └── test.st ├── TestArrayLiterals │ ├── expected.txt │ └── test.st ├── TestBlockAssignment │ ├── expected.txt │ └── test.st ├── TestBlockReturn │ ├── expected.txt │ └── test.st ├── TestBlockReturningABlock │ ├── expected.txt │ └── test.st ├── TestCascadedMessages │ ├── expected.txt │ └── test.st ├── TestClassMethods1 │ ├── expected.txt │ └── test.st ├── TestClassMethods2 │ ├── expected.txt │ └── test.st ├── TestClassMethods3 │ ├── expected.txt │ └── test.st ├── TestClassVariables │ ├── expected.txt │ └── test.st ├── TestClassVariables2 │ ├── expected.txt │ └── test.st ├── TestComplexBoxing │ ├── expected.txt │ └── test.st ├── TestCountingWhileTrue │ ├── expected.txt │ └── test.st ├── TestDealloc │ ├── expected.txt │ └── test.st ├── TestDeeplyNestedBlocks │ ├── expected.txt │ └── test.st ├── TestFloatBoxing │ ├── expected.txt │ └── test.st ├── TestInstanceVariables │ ├── expected.txt │ └── test.st ├── TestIntArithmetic │ ├── expected.txt │ └── test.st ├── TestIntegerAddition │ ├── expected.txt │ └── test.st ├── TestIntegerUpTo │ ├── expected.txt │ └── test.st ├── TestIsAlphabetic │ ├── expected.txt │ └── test.st ├── TestJustAnInteger │ ├── expected.txt │ └── test.st ├── TestKVC │ ├── expected.txt │ └── test.st ├── TestMutRecursiveClassDefs │ ├── expected.txt │ └── test.st ├── TestNSPointBoxing │ ├── expected.txt │ └── test.st ├── TestNSRangeBoxing │ ├── expected.txt │ └── test.st ├── TestNSRectBoxing │ ├── expected.txt │ └── test.st ├── TestNSSizeBoxing │ ├── expected.txt │ └── test.st ├── TestNestedBlocks │ ├── expected.txt │ └── test.st ├── TestNonLocalReturn │ ├── expected.txt │ └── test.st ├── TestNonLocalReturn2 │ ├── expected.txt │ └── test.st ├── TestOperatorDefinition │ ├── expected.txt │ └── test.st ├── TestPolymorphicSelectors │ ├── expected.txt │ └── test.st ├── TestScopes │ ├── expected.txt │ └── test.st ├── TestSimpleSelect │ ├── expected.txt │ └── test.st ├── TestTimesRepeat │ ├── expected.txt │ └── test.st ├── TestTranscript │ ├── expected.txt │ └── test.st ├── TestYourself │ ├── expected.txt │ └── test.st ├── XFAILPrototypes │ ├── expected.txt │ └── test.st ├── XFAILRtainOnlyOnce │ ├── expected.txt │ └── test.st ├── newtest.sh ├── runall.sh └── runtest.sh ├── lemon.c ├── lempar.c ├── smalltalk.vim └── smalltalk.y /Benchmark/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | 4 | # 5 | # Application 6 | # 7 | VERSION = 0.1 8 | TOOL_NAME = benchmark 9 | 10 | ${TOOL_NAME}_LANGUAGES = English 11 | 12 | ${TOOL_NAME}_OBJC_FILES = \ 13 | main.m\ 14 | 15 | ${TOOL_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value\ 16 | -fno-objc-legacy-dispatch 17 | ${TOOL_NAME}_LDFLAGS += -g -lgmp -lEtoileFoundation -lgnustep-gui\ 18 | -L/usr/local/lib\ 19 | -lSmalltalkSupport\ 20 | -lLanguageKitRuntime\ 21 | smalltalk.optimised.o 22 | 23 | #ADDITIONAL_OBJCFLAGS += -march=i686 24 | 25 | ${TOOL_NAME}_CFLAGS += -Wno-implicit -g -O0 26 | 27 | #SMALLTALK_FILES += prototype.st 28 | SMALLTALK_FILES += fib.st 29 | 30 | all:: smalltalk.optimised.o 31 | 32 | clean:: 33 | rm -f smalltalk.optimised.* *.bc 34 | 35 | include $(GNUSTEP_MAKEFILES)/aggregate.make 36 | include $(GNUSTEP_MAKEFILES)/tool.make 37 | 38 | smalltalk.optimised.o: ${SMALLTALK_FILES} 39 | @sh compile.sh ${SMALLTALK_FILES} 40 | -------------------------------------------------------------------------------- /Benchmark/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Generate bitcode for all of the Smalltalk files 4 | for ST in $@ 5 | do 6 | echo Compiling $ST to LLVM bitcode... 7 | edlc -c -f $ST -v LKLowerIfTrueTransform 8 | done 9 | 10 | # Link the bitcode together 11 | BC=`echo $@ | sed 's/\.st/\.bc/g'` 12 | echo Linking bitcode files... 13 | llvm-link -f -o smalltalk.bc \ 14 | ${GNUSTEP_LOCAL_ROOT}/Library/Frameworks/LanguageKitCodeGen.framework/Versions/0/Resources/MsgSendSmallInt.bc\ 15 | $BC 16 | 17 | # Optimise the bitcode 18 | echo Running optimiser... 19 | opt -load /usr/local/lib/libGNUObjCRuntime.so -objc-arc-expand -objc-arc -objc-arc-aa -objc-arc-apelim -objc-arc-contract -O3 smalltalk.bc -o smalltalk.optimised.bc 20 | opt -objc-arc-expand -objc-arc -objc-arc-aa -objc-arc-apelim -objc-arc-contract -O3 smalltalk.bc -o smalltalk.optimised.bc 21 | 22 | # Generate assembly 23 | echo Compiling bitcode... 24 | llc smalltalk.optimised.bc 25 | 26 | # Assemble a .o file 27 | echo Assembling object file... 28 | gcc -c -g smalltalk.optimised.s 29 | -------------------------------------------------------------------------------- /Benchmark/fib.st: -------------------------------------------------------------------------------- 1 | << types = '{"fibonacci:" = "i12@0:4i8";}'>> 2 | NSObject subclass: SmalltalkFibonacci [ 3 | | f | 4 | 5 | fib: n [ 6 | | c ret | 7 | c := (n < 2). 8 | c ifTrue:[ 9 | ret := 1. 10 | nil. 11 | ] ifFalse:[ 12 | ret := (self fib:(n - 1)) 13 | + (self fib:(n - 2)). 14 | nil. 15 | ]. 16 | ^ret. 17 | ] 18 | fibonacci: n [ 19 | | c ret | 20 | c := (n < 2). 21 | c ifTrue:[ 22 | ret := 1. 23 | nil. 24 | ] ifFalse:[ 25 | ret := (self fibonacci:(n - 1)) 26 | + (self fibonacci:(n - 2)). 27 | nil. 28 | ]. 29 | ^ret. 30 | ] 31 | runNative: i [ (self fib: i) ] 32 | run [ 33 | "(self fibonacci:40) log." 34 | (self fib:40) log. 35 | ] 36 | ] 37 | -------------------------------------------------------------------------------- /Benchmark/prototype.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkPrototype 2 | [ 3 | value: a [ ^a. ] 4 | 5 | block 6 | [ 7 | ^ [ :x | x ]. 8 | ] 9 | 10 | makePrototype [ 11 | | a | 12 | a := NSObject new. 13 | a becomePrototype. 14 | a setValue:[ :this :aValue | aValue ] forKey:'value:'. 15 | a setValue:[ :this :aValue | aValue log ] forKey:'logValue:'. 16 | a setValue:[ :this :aValue | ETTranscript show:aValue ] 17 | forKey:'showValue:'. 18 | ^a. 19 | ] 20 | ] 21 | -------------------------------------------------------------------------------- /Benchmark/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTest 2 | [ 3 | test 4 | [ 5 | "'Testing...' log." 6 | 'foo' lowercaseString. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Compiler/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007, David Chisnall 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | * Neither the name of the Étoilé project, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | 16 | 17 | -------------------------------------------------------------------------------- /Compiler/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | ifeq ($(test), yes) 4 | SUBPROJECTS += Test 5 | endif 6 | 7 | # 8 | # Application 9 | # 10 | VERSION = 0.4.2 11 | TOOL_NAME = edlc 12 | 13 | ${TOOL_NAME}_LANGUAGES = English 14 | 15 | ${TOOL_NAME}_OBJC_FILES = \ 16 | main.m 17 | 18 | MAN1_PAGES = edlc.1 19 | 20 | ${TOOL_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 21 | ${TOOL_NAME}_LDFLAGS += -g -lgmp -lEtoileFoundation -lgnustep-gui\ 22 | -L/usr/local/lib 23 | # Hacks to compile without installing the frameworks first. 24 | ${TOOL_NAME}_LDFLAGS += \ 25 | -lSmalltalkSupport \ 26 | -lLanguageKit 27 | 28 | ${TOOL_NAME}_CFLAGS += -Wno-implicit -g 29 | 30 | include $(GNUSTEP_MAKEFILES)/aggregate.make 31 | -include ../../etoile.make 32 | include $(GNUSTEP_MAKEFILES)/tool.make 33 | -------------------------------------------------------------------------------- /Compiler/HACKING: -------------------------------------------------------------------------------- 1 | Pragmatic Smalltalk 2 | =================== 3 | 4 | Overview 5 | -------- 6 | 7 | This is a smalltalk JIT and static compiler, producing native code running on 8 | top of an Objective-C runtime for the object model. The code is in three main 9 | parts: 10 | 11 | 1) The parser and AST takes a string as input and constructs a Smalltalk 12 | abstract syntax tree. 13 | 14 | 2) The code generator, hidden behind an abstract interface, produces native 15 | code. Currently, there is only one implementation of this. It uses LLVM and 16 | shares code with the Objective-C front end for LLVM; clang. 17 | 18 | 3) The support libraries, such as MsgSendSmallInt and BlockClosure implement 19 | parts of Smalltalk that are not already present in Objective-C / OpenStep. 20 | 21 | The first two of these are in the SmalltalkKit directory. The last is in the 22 | Support directory. 23 | 24 | Building 25 | -------- 26 | 27 | If you have LLVM, Lemon, and EtoileFoundation installed, GNUstep make should 28 | build without problems. If it doesn't, please send me a bug report. 29 | 30 | Hacking 31 | ------- 32 | 33 | At the time of writing, the code contains 39 'FIXME's and 12 'TODO's - patches 34 | for any of these are welcome, please post them on [the code review site 35 | ](http://review.etoileos.com). 36 | 37 | Note that MsgSendSmallInt.bc is an LLVM bitcode file. This is used as a 38 | template for code generation of message sends to small integers, allowing them 39 | to be inlined. If you modify the corresponding .m file, please use clang to 40 | regenerate this file. 41 | 42 | The big project still to do is add a type inference engine. If we can 43 | guarantee that an object is or isn't a SmallInt, we can get some performance 44 | improvements. Since methods never return SmallInts (although they might return 45 | unboxed integers, which are handled differently), we can use this information 46 | to eliminate a number of branches. Beyond this, if we can guess (even if we 47 | are wrong some of the time) the class of an object then we can get another 48 | performance boost from speculative inlining of methods. 49 | 50 | There is currently no real garbage collection for Smalltalk. This needs to be 51 | done in a way that can interoperate with non-GC'd Objective-C, to allow ObjC to 52 | be used for performance critical parts without GC overhead. This should be 53 | done by integrating the cycle detector in GCKit and marking Smalltalk objects 54 | as black. 55 | 56 | Summary of Missing Features 57 | --------------------------- 58 | 59 | Still missing for 1.0: 60 | 61 | - Full implementation of Smalltalk-80 SmallInt messages. 62 | 63 | Still missing for 2.0: 64 | 65 | - Support for floating point values. 66 | - Type inference engine. 67 | - More complete implementation of Smalltalk-80 objects (ideally as class-name 68 | mappings and categories on OpenStep objects where possible.) 69 | - Working support for the new runtime. 70 | 71 | Still missing for 3.0: 72 | 73 | - Self-style prototype support. 74 | - World domination. 75 | 76 | 77 | Have fun! 78 | 79 | - David Chisnall 80 | -------------------------------------------------------------------------------- /Compiler/Native/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | 4 | # 5 | # Application 6 | # 7 | VERSION = 0.1 8 | TOOL_NAME = sttool 9 | 10 | ${TOOL_NAME}_LANGUAGES = English 11 | 12 | ${TOOL_NAME}_OBJC_FILES = \ 13 | tst.m\ 14 | 15 | MAN1_PAGES = edlc.1 16 | 17 | ${TOOL_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 18 | ${TOOL_NAME}_LDFLAGS += -g -lgmp -lEtoileFoundation -lgnustep-gui\ 19 | -L/usr/local/lib\ 20 | -lSmalltalkSupport\ 21 | smalltalk.optimised.o 22 | 23 | all:: smalltalk.optimised.o 24 | 25 | ${TOOL_NAME}_CFLAGS += -Wno-implicit -g 26 | 27 | include $(GNUSTEP_MAKEFILES)/aggregate.make 28 | include $(GNUSTEP_MAKEFILES)/tool.make 29 | 30 | test.bc: test.st 31 | @echo Compiling test.st... 32 | @edlc -c -f test.st 33 | 34 | smalltalk.bc: test.bc 35 | @echo Linking Smalltalk... 36 | @llvm-link $(GNUSTEP_LOCAL_ROOT)/Library/Frameworks/LanguageKitCodeGen.framework/Versions/0/Resources/MsgSendSmallInt.bc test.bc -o smalltalk.bc 37 | 38 | smalltalk.optimised.bc: smalltalk.bc 39 | @echo Optimising Smalltalk... 40 | @opt -O3 smalltalk.bc -o smalltalk.optimised.bc 41 | 42 | smalltalk.optimised.s: smalltalk.optimised.bc 43 | @echo Generative code from Smalltalk... 44 | @llc smalltalk.optimised.bc 45 | 46 | smalltalk.optimised.o: smalltalk.optimised.s 47 | @echo Assembling Smalltalk... 48 | @gcc -c smalltalk.optimised.s -g 49 | -------------------------------------------------------------------------------- /Compiler/Native/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: TestBlock 2 | [ 3 | run: aBlock [ 4 | aBlock log. 5 | 'Evaluating block' log. 6 | aBlock value log. 7 | ] 8 | ] 9 | NSObject subclass: SmalltalkTool 10 | [ 11 | run [ 12 | | task | 13 | #aSymbol log. 14 | (TestBlock new) log. 15 | (NSObject new) log. 16 | (NSString new) log. 17 | "Test that messages with two arguments are parsed correctly" 18 | self log:'a' and:'b'. 19 | nil data. 20 | self log. 21 | "Test instantiation of other Smalltalk classes" 22 | self test:(TestBlock new). 23 | ] 24 | log [ 25 | 'Testing superclass message log.' log. 26 | super log. 27 | ] 28 | 29 | log:a and:b [ 30 | a log. 31 | b log. 32 | ] 33 | 34 | test: r [ 35 | | a b c| 36 | "Test array creation." 37 | a := {NSObject new. NSString new. NSNumber new}. 38 | a log. 39 | "Test passing Smalltalk blocks to Objective-C objects" 40 | b := a map:[ :x | x log. x class. ]. 41 | b map:[ :x | x log. x. ]. 42 | a insertObject:'test' atIndex:2. 43 | b := a objectAtIndex:2. 44 | "You can't do this in Objective-C:" 45 | (a objectAtIndex:'2') log. 46 | ((a objectAtIndex:2) == 'test') ifTrue:[ 'Array insert (auto-unboxing) worked!' log. ]. 47 | a log. 48 | r log. 49 | "Test SmallInt messaging" 50 | b := 12. 51 | c := b + 5. 52 | b stringValue log. 53 | 'Comparison result:' log. 54 | ('wibble' == 'wible') log. 55 | ('wibble' == 'wibble') log. 56 | ('wibble' = 'wible') log. 57 | (12 = 12) log. 58 | ('wibble' = 'wibble') log. 59 | 'Wibble?' log. 60 | self wibble:c. 61 | b log. 62 | a := NSMutableArray array. 63 | a log. 64 | self objectAtIndex: 12. 65 | "Test passing blocks to other bits of Smalltalk code" 66 | r run:[ a log. ]. 67 | "Test message sends to nil." 68 | nil log. 69 | "Load an ObjC symbolic constant" 70 | @NSViewMaxYMargin log. 71 | (1 < 2) ifTrue:[ '1 < 2' log. ]. 72 | ] 73 | objectAtIndex: i [ 74 | "This parameter will be passed as an unsigned int, because NSArray 75 | defines the type of this selector." 76 | 'Boxed then unboxed value: ' log. 77 | i log. 78 | ] 79 | 80 | wibble: a [ 81 | 'wibble called' log. 82 | a log. 83 | ^a. 84 | ] 85 | ] 86 | -------------------------------------------------------------------------------- /Compiler/Native/tst.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol Tool 4 | - (void) run; 5 | @end 6 | 7 | int main(void) 8 | { 9 | [NSAutoreleasePool new]; 10 | [[[NSClassFromString(@"SmalltalkTool") alloc] init] run]; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /Compiler/README: -------------------------------------------------------------------------------- 1 | Pragmatic Smalltalk 2 | ==================== 3 | 4 | This is an implementation of Smalltalk designed to run on top of an Objective-C runtime and 5 | 6 | Status 7 | ------ 8 | 9 | Currently, JIT is working, static compilation is not. 10 | 11 | Large parts of Smalltalk don't work. Instance variables which are not objects, 12 | and returns from blocks are the big things that are broken. Grep the source 13 | code for 'FIXME' and 'TODO' for a clearer picture. 14 | 15 | Dependencies 16 | ------------ 17 | 18 | The parser is generated using the Lemon parser generator from SQLite (public domain). 19 | Code generation uses the LLVM compiler infrastructure. 20 | Various parts of EtoileFoundation are used (mainly macros). 21 | These must all be installed to build. 22 | 23 | If you are not developing the compiler, it is *strongly* recommended that you 24 | do a release build of LLVM (it defaults to a debug build). Release builds run 25 | approximately 10 times faster and are significantly smaller. 26 | 27 | NOTE: Due to recent changes in LLVM APIs, LLVM 2.3 is not sufficient to build. 28 | A recent checkout of trunk is required. The version of Pragmatic Smalltalk in 29 | trunk will track LLVM trunk. Versions in releases will work with a specific 30 | LLVM release. 31 | -------------------------------------------------------------------------------- /Compiler/edlc.1: -------------------------------------------------------------------------------- 1 | .Dd July 24, 2008 2 | .Dt ST 1 3 | .Os 4 | .Sh NAME 5 | .Nm edlc 6 | .Nd Etoile Dynamic Language Compiler 7 | .Sh SYNOPSIS 8 | .Nm du 9 | .Op Fl t 10 | .Op Fl c 11 | .Op Fl C Ar class 12 | .Op Fl l Ar framework 13 | .Op Fl L Ar plist 14 | { 15 | .Fl f Ar file | 16 | .Fl b Ar bundle 17 | } 18 | .Sh DESCRIPTION 19 | The 20 | .Nm 21 | utility loads, compiles, and executes an OpenStep application written 22 | in Smalltalk. Either the 23 | .Fl f 24 | or 25 | .Fl b 26 | options must be specified, indicating a Smalltalk file or bundle to load, 27 | respectively. Smalltalk bundles may contain resources, lists of frameworks to 28 | load, and may implement GUI applications or command-line tools. Individual 29 | files may only implement command-line tools unless they handle the creation of 30 | the NSApplication and loading of resources themselves. 31 | .Pp 32 | Options are as follows: 33 | .Bl -tag -width Ds 34 | .It Fl b Ar bundle 35 | Specify the Smalltalk bundle to load. 36 | .It Fl c 37 | Statically compile (to LLVM bitcode) and exit. Do not run the program. 38 | .It Fl C Ar class 39 | Specify the class to instantiate. Instances of this class must respond to the 40 | run message. 41 | .It Fl f Ar file 42 | Specify the single Smalltalk source file to load. 43 | .It Fl F Ar framework 44 | Specify a single framework to load. 45 | .It Fl l Ar library 46 | Specify a single library to load. 47 | .It Fl L Ar plist 48 | Specify a property list file containing an array of framework names to load. 49 | .It Fl t 50 | Print summary of CPU time and memory usage after the command has executed. 51 | .It Fl v 52 | Causes the specified AST transform to be applied. 53 | .Sh BUGS 54 | Smalltalk bundles are not yet working. 55 | .Sh HISTORY 56 | A 57 | .Nm 58 | command appeared in Etoile 0.4 . 59 | .Sh AUTHORS 60 | The Pragmatic Smalltalk Compiler was written by David Chisnall 61 | 62 | .Sh Copyright 63 | The Pragmatic Smalltalk compiler is Copyright 2008 David Chisnall and is 64 | released under the MIT license. See COPYING for more information. 65 | -------------------------------------------------------------------------------- /Compiler/examples/1log.st: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S edlc -f 2 | 3 | NSObject subclass: SmalltalkTool [ 4 | run [ 5 | 1 log. 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Compiler/examples/a.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | run [ 4 | | a | 5 | [ :x | x log. ] value: 'foo'. 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Compiler/examples/addMethod.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | | count | 4 | ETTranscript show: (self class) ; cr. 5 | count := 0. 6 | self class addInstanceMethod: #testMethod fromBlock: 7 | [ :self | 8 | count := count + 1. 9 | ETTranscript show: count ; show: self ; cr 10 | ]. 11 | self testMethod. 12 | self testMethod. 13 | self testMethod 14 | ] 15 | ] 16 | -------------------------------------------------------------------------------- /Compiler/examples/appkit.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | 4 | run 5 | [ | task | 6 | NSApplication sharedApplication setDelegate: self. 7 | NSApplication sharedApplication run. 8 | ] 9 | 10 | applicationDidFinishLaunching: notif 11 | [ 12 | 'Hello world!' log. 13 | ] 14 | ] 15 | -------------------------------------------------------------------------------- /Compiler/examples/array.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | run 4 | [ 5 | |a| 6 | a := {'1'. '2'. '3'.}. 7 | a addObject:1. 8 | (a objectAtIndex:3) log. 9 | a log. 10 | a count log. 11 | ] 12 | ] 13 | 14 | -------------------------------------------------------------------------------- /Compiler/examples/b.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | 3 | do:b [ b value: 'wibble'. ] 4 | run [ 5 | self do:[ :x | 1 ifTrue:[ x log. ]. ] . 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Compiler/examples/bench.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | run[] 4 | 5 | multiply:a by:b 6 | [ 7 | ^a * b. 8 | ] 9 | ] 10 | -------------------------------------------------------------------------------- /Compiler/examples/block.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | 3 | do:b [ b value: 'wibble'. ] 4 | run [ 5 | | ret | 6 | self do:[ :x | 1 ifTrue:[ x log. ]. ] . 7 | ret := 'Ret incorrectly set'. 8 | self do:[ :x | ret := x. ]. 9 | ret log. 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /Compiler/examples/cat.st: -------------------------------------------------------------------------------- 1 | NSObject extend [ 2 | wibble [ 3 | 'Yes!' log. 4 | ] 5 | ] 6 | NSObject subclass: SmalltalkTool [ 7 | run [ 8 | 'Did categories work?' log. 9 | (NSObject new) wibble. 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /Compiler/examples/cat2.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | | foo | 3 | run [ 4 | 'Setting ivar' log. 5 | foo := 12. 6 | 'set ivar' log. 7 | self wibble. 8 | ] 9 | ] 10 | SmalltalkTool extend [ 11 | wibble [ 'foo' log. foo log. ] 12 | ] 13 | -------------------------------------------------------------------------------- /Compiler/examples/dispatch.st: -------------------------------------------------------------------------------- 1 | " Example showing how to use libdispatch directly from Smalltalk. Invoke with: 2 | $ edlc -f dispatch.st -l dispatch 3 | " 4 | << headers='("dispatch/dispatch.h", "unistd.h")' >> 5 | NSObject subclass: SmalltalkTool [ 6 | run [ 7 | | queue count | 8 | queue := C dispatch_get_global_queue: { 0. 0 }. 9 | ETTranscript show: 'main thread' ; cr . 10 | count := 1. 11 | 1 to: 10 do: [ 12 | C dispatch_async: { queue . 13 | [ 14 | ETTranscript show: 'Another thread' ; 15 | show: count ; cr . 16 | count := count + 1 17 | ] } ] . 18 | C sleep: 1. 19 | ETTranscript show: 'Threads used: ' ; show: count ; cr. 20 | ] 21 | ] 22 | -------------------------------------------------------------------------------- /Compiler/examples/dispatch_locked.st: -------------------------------------------------------------------------------- 1 | " Example showing how to use libdispatch directly from Smalltalk. Invoke with: 2 | $ edlc -f dispatch.st -l dispatch 3 | " 4 | << headers='("dispatch/dispatch.h", "unistd.h")' >> 5 | NSObject subclass: SmalltalkTool [ 6 | run [ 7 | | queue count lock | 8 | lock := NSLock new. 9 | queue := C dispatch_get_global_queue: { 0. 0 }. 10 | ETTranscript show: 'main thread' ; cr . 11 | count := 1. 12 | 1 to: 10 do: [ 13 | C dispatch_async: { queue . 14 | [ 15 | lock lock. 16 | ETTranscript show: 'Another thread' ; 17 | show: count ; cr . 18 | count := count + 1 . 19 | lock unlock 20 | ] } ] . 21 | C sleep: 1. 22 | ETTranscript show: 'Threads used: ' ; show: count ; cr. 23 | ] 24 | ] 25 | -------------------------------------------------------------------------------- /Compiler/examples/empty.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | 'Test string' log. 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /Compiler/examples/enum.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool 3 | [ 4 | run [ 5 | ETTranscript show: 'NSNotFound is: '; show: (C enumValue: NSNotFound) ; cr. 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Compiler/examples/eric.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | 5 log. 4 | ] 5 | ] 6 | 7 | -------------------------------------------------------------------------------- /Compiler/examples/fib.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | | f | 3 | 4 | run [ 5 | self fibonacci: 30. 6 | ] 7 | fibonacci: n [ 8 | | c ret | 9 | c := (n < 2). 10 | c ifTrue:[ 11 | ret := 1. 12 | ] ifFalse:[ 13 | ret := (self fibonacci:(n - 1)) 14 | + (self fibonacci:(n - 2)). 15 | ]. 16 | ^ret. 17 | ] 18 | ] 19 | -------------------------------------------------------------------------------- /Compiler/examples/fib2.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | | f | 3 | 4 | init [ 5 | f := NSMutableArray new. 6 | f addObject:1. 7 | f addObject:1. 8 | ^self. 9 | ] 10 | run [] 11 | fibonacci: n [ 12 | | ret | 13 | (n < (f count)) 14 | ifTrue:[ 15 | ret := f objectAtIndex:n. 16 | ] ifFalse:[ 17 | ret := (self fibonacci:(n - 1)) 18 | + (self fibonacci:(n - 2)). 19 | f insertObject:ret atIndex:n. 20 | ]. 21 | ret log. 22 | ^ret. 23 | ] 24 | 25 | intValue [ 26 | | a | 27 | a := 6. 28 | a := a + 7. 29 | ^a. ] 30 | ] 31 | -------------------------------------------------------------------------------- /Compiler/examples/float.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | run [ 4 | | a | 5 | "You can explicitly create floats from most objects." 6 | a := '1.23e3' floatValue. 7 | "Or using float literals" 8 | a := 65.23. 9 | "Or you can do it implicitly" 10 | a := a + '2.34'. 11 | a := a + 12. 12 | "Floats are objects" 13 | a log. 14 | "Currently instances of the BoxedFloat class" 15 | a class log. 16 | ] 17 | ] 18 | -------------------------------------------------------------------------------- /Compiler/examples/foo.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | | a | 4 | a := NSObject alloc init. 5 | a log. 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Compiler/examples/gt.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | (100 > 200) log. 4 | (200 > 100) log. 5 | (100 < 200) log. 6 | (200 < 100) log. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Compiler/examples/if.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | 1 ifTrue:[ 'true'. ]. 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /Compiler/examples/int.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [] 3 | 4 | intValue [ 5 | | a | 6 | a := 6. 7 | a := a + 7. 8 | ^a. 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /Compiler/examples/ivar.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | | a | 3 | run [ 4 | a := 1. 5 | true ifTrue: [ a log. a := 'wibble' ]. 6 | a log. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Compiler/examples/localblock.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | | i | 3 | run [ 4 | i := 'foo'. 5 | self test:100. 6 | ] 7 | test: n [ 8 | | a| 9 | a := 12. 10 | 1 ifTrue:[ self log. i log. a log. n log. ]. 11 | ] 12 | 13 | ] 14 | -------------------------------------------------------------------------------- /Compiler/examples/ls.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: LS 2 | [ 3 | run 4 | [ 5 | | fm files out | 6 | fm := NSFileManager defaultManager. 7 | files := fm directoryContentsAtPath:'.'. 8 | out := NSFileHandle fileHandleWithStandardOutput. 9 | files foreach:[ :x | x printOn:out. '\n' printOn:out. ]. 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /Compiler/examples/mult.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | | a | 4 | "This simple example just repeatedly multiplies a number by 12. It 5 | demonstrates the overflow capabilities of Smalltalk. At some point in 6 | the middle the value will be promoted to a big integer object - there 7 | will never be a loss of precision." 8 | a := 123. 9 | 1 to: 20 do: [ 10 | a := a * 12. 11 | a log. 12 | ] 13 | ] 14 | ] 15 | -------------------------------------------------------------------------------- /Compiler/examples/nico.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run 3 | [ 4 | | x v | 5 | x := 'test'. v := x componentsSeparatedByString: ':'. 6 | x log. v log. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Compiler/examples/nsrange.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ | range | 3 | range := (NSValue rangeWithLocation:0 length:9). 4 | 'Create range: ' log. 5 | range log. 6 | ('Substring of longer string' substringWithRange:range) log. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Compiler/examples/null.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | run: aBlock [ 4 | aBlock log. 5 | 'Evaluating block' log. 6 | aBlock value log. 7 | ] 8 | run [ 9 | self run:[ 'foo' log. ]. 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /Compiler/examples/overflow.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | 3 | run [ 4 | | a | 5 | 'Testing multiplication' log. 6 | a := 2. 7 | a := a * a. 8 | a log. 9 | a := a * a. 10 | a log. 11 | a := a * a. 12 | a log. 13 | a := a * a. 14 | a log. 15 | a := a * a. 16 | a log. 17 | 'Testing addition' log. 18 | a := 1000000000. 19 | a log. 20 | a := a + a. 21 | a log. 22 | a := a + a. 23 | a log. 24 | a := a + a. 25 | a log. 26 | a := a + a. 27 | a log. 28 | 'Testing subtraction' log. 29 | a := 0 - 1000000000. 30 | a log. 31 | a := a - 1000000000. 32 | a log. 33 | a := a - 1000000000. 34 | a log. 35 | a := a - 1000000000. 36 | a log. 37 | ] 38 | ] 39 | -------------------------------------------------------------------------------- /Compiler/examples/retainblock.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | | block | 3 | run [ 4 | self setBlock. 5 | self callBlock. 6 | ] 7 | setBlock [ 8 | | a | 9 | a := 'Local variable'. 10 | block := [ a log. ]. 11 | ] 12 | callBlock [ 13 | 'Testing retained block:' log. 14 | block value. 15 | ] 16 | ] 17 | -------------------------------------------------------------------------------- /Compiler/examples/script.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | " Run this with -l ScriptKit. It will close the active Typewriter window" 4 | 5 | Tell application:'Typewriter' to:[ :d | 6 | (d objectForKey:'Application') sendAction:#performClose: 7 | to:nil 8 | from:nil . 9 | ] . 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /Compiler/examples/self.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ self foo. ] 3 | foo [ 'wibble' log. ] 4 | ] 5 | -------------------------------------------------------------------------------- /Compiler/examples/serial.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | 'Passing self in a block...' log. 4 | 1 ifTrue: [ self wibble. (NSObject new) log. ]. 5 | ] 6 | 7 | wibble [ 8 | 'Calling self method in block' log. 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /Compiler/examples/shell.st: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S edlc -f 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | 'Smalltalk tool executed with these arguments:' log. 5 | NSProcessInfo processInfo arguments mappedCollection log. 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Compiler/examples/simpleblock.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | 3 | do:b [ b value: 'wibble'. ] 4 | 5 | run [ 6 | | return | 7 | self do:[ :x | return := x. ]. 8 | return log. 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /Compiler/examples/str.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | |str | 4 | str := 'foo'. 5 | str log. 6 | str := str stringByAppendingString:'bar'. 7 | str log. 8 | str := 'foo' mutableCopy. 9 | str log. 10 | str appendString:'bar'. 11 | str log. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Compiler/examples/subclass.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: Test [ 2 | wibble [ 3 | 'wibble' log. 4 | ] 5 | ] 6 | Test subclass: SmalltalkTool [ 7 | run [ 8 | self wibble. 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /Compiler/examples/sym.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | self performSelector:'wibble'. 4 | ] 5 | wibble [ 6 | 'wibble called' log. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Compiler/examples/t1.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: Foo [ 2 | wibble [ 3 | 'foo' log. 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /Compiler/examples/t2.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | Foo new wibble. 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /Compiler/examples/test.st: -------------------------------------------------------------------------------- 1 | << types = '{"data" = "@8@0:4"}'>> 2 | NSObject subclass: TestBlock 3 | [ 4 | run: aBlock [ 5 | aBlock log. 6 | 'Evaluating block' log. 7 | aBlock value log. 8 | ] 9 | ] 10 | NSObject subclass: SmalltalkTool 11 | [ 12 | | +foo i | 13 | init [] 14 | +alloc [ 15 | foo := 'Class variable value set in class method'. 16 | 'Class method alloc called' log. 17 | ^super alloc. 18 | ] 19 | cascade1 [ 20 | foo log. 21 | 'First cascade message sent' log. 22 | ] 23 | cascade2 [ 24 | 'Second cascade message sent' log. 25 | ] 26 | testNestedBlocks[ 27 | | a | 28 | 'testing nested blocks' log. 29 | i := 'Accessing ivar from nested block'. 30 | a := 'Accessing local from nested block'. 31 | 1 ifTrue:[ 32 | 1 ifTrue:[ 33 | 1 ifTrue:[ 34 | a log. 35 | a := 'Set local in nested block'. 36 | i log. 37 | i := 'Set ivar in nested block'. 38 | ] 39 | ]. 40 | ]. 41 | i log. 42 | a log. 43 | ] 44 | run [ 45 | | task | 46 | "Test cascade messages:" 47 | self cascade1; cascade2 ; cascade1; cascade2. 48 | (TestBlock new) log. 49 | (NSObject new) log. 50 | (NSString new) log. 51 | "Test that messages with two arguments are parsed correctly" 52 | self log:'a' and:'b'. 53 | nil data. 54 | self log. 55 | "Test instantiation of other Smalltalk classes" 56 | self test:(TestBlock new). 57 | ] 58 | log [ 59 | 'Testing superclass message log.' log. 60 | super log. 61 | ] 62 | 63 | log:a and:b [ 64 | a log. 65 | b log. 66 | ] 67 | 68 | test: r [ 69 | | a b c| 70 | "Test array creation." 71 | a := {NSObject new. NSString new. NSNumber new}. 72 | a log. 73 | "Test passing Smalltalk blocks to Objective-C objects" 74 | b := a map:[ :x | x log. x class. ]. 75 | b map:[ :x | x log. x. ]. 76 | a insertObject:'test' atIndex:2. 77 | b := a objectAtIndex:2. 78 | "You can't do this in Objective-C:" 79 | (a objectAtIndex:'2') log. 80 | ((a objectAtIndex:2) == 'test') ifTrue:[ 'Array insert (auto-unboxing) worked!' log. ]. 81 | a log. 82 | r log. 83 | "Test SmallInt messaging" 84 | b := 12. 85 | c := b + 5. 86 | b stringValue log. 87 | 'Comparison result:' log. 88 | ('wibble' == 'wible') log. 89 | ('wibble' == 'wibble') log. 90 | ('wibble' = 'wible') log. 91 | (12 = 12) log. 92 | ('wibble' = 'wibble') log. 93 | 'Wibble?' log. 94 | self wibble:c. 95 | b log. 96 | a := NSMutableArray array. 97 | a log. 98 | self objectAtIndex: 12. 99 | "Test passing blocks to other bits of Smalltalk code" 100 | r run:[ a log. ]. 101 | "Test message sends to nil." 102 | nil log. 103 | "Load an ObjC symbolic constant" 104 | @NSViewMaxYMargin log. 105 | (1 < 2) ifTrue:[ '1 < 2' log. ]. 106 | self testNestedBlocks. 107 | #symbol log. 108 | 'Testing if empty methods return self:' log. 109 | self init log. 110 | "A really big integer:" 111 | 10000000000000000 log. 112 | (2 * '3') log. 113 | ] 114 | objectAtIndex: i [ 115 | "This parameter will be passed as an unsigned int, because NSArray 116 | defines the type of this selector." 117 | 'Boxed then unboxed value: ' log. 118 | i log. 119 | ] 120 | 121 | wibble: a [ 122 | 'wibble called' log. 123 | a log. 124 | ^a. 125 | ] 126 | ] 127 | -------------------------------------------------------------------------------- /Compiler/old/ExecutionContext.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * Skeleton for an interpreter context. Not yet used. Might not ever be used. 5 | * Go away and stop looking at this code (or implement an interpreter). 6 | */ 7 | @interface ExecutionContext : NSObject { 8 | SymbolTable * symbols; 9 | id * args; 10 | NSMapTable * locals; 11 | } 12 | - (id) initWithArgs:(id*)argv; 13 | - (id) getArg:(int)argIndex; 14 | - (void) setArg:(id)arg atIndex:(int)argIndex; 15 | @end 16 | -------------------------------------------------------------------------------- /Compiler/old/ExecutionContext.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation ExecutionContext 4 | - (id) initWithArgs:(id*)argv 5 | { 6 | SELFINIT; 7 | args = argv; 8 | return SELF; 9 | } 10 | - (id) getArg:(int)argIndex 11 | { 12 | return args[argIndex]; 13 | } 14 | - (void) setArg:(id)arg atIndex:(int)argIndex 15 | { 16 | args[argIndex] = arg; 17 | } 18 | @end 19 | -------------------------------------------------------------------------------- /Compiler/old/NSObject+ReplaceMethods.h: -------------------------------------------------------------------------------- 1 | #include 2 | @interface NSObject (RuntimeHackery) 3 | + (int) replaceMethodForSelector:(SEL)aSelector with:(IMP)aMethod; 4 | + (int) addMethod:(IMP)aMethod forSelectorNamed:(char*)aSelector; 5 | @end 6 | -------------------------------------------------------------------------------- /Compiler/old/NSObject+ReplaceMethods.m: -------------------------------------------------------------------------------- 1 | #import "NSObject+ReplaceMethods.h" 2 | 3 | extern void __objc_update_dispatch_table_for_class (Class); 4 | extern void __objc_register_selectors_from_list (MethodList_t); 5 | 6 | @implementation NSObject (RuntimeHackery) 7 | + (int) replaceMethodForSelector:(SEL)aSelector with:(IMP)aMethod 8 | { 9 | MethodList_t methods = ((Class)self)->methods; 10 | while(methods != NULL) 11 | { 12 | for(unsigned int i=0 ; imethod_count ; i++) 13 | { 14 | Method_t method = &methods->method_list[i]; 15 | //We perform a string comparison, because == does not work on SEL 16 | if([NSStringFromSelector(method->method_name) isEqualToString:NSStringFromSelector(aSelector)]) 17 | { 18 | NSLog(@"Replacing method..."); 19 | method->method_imp = aMethod; 20 | __objc_update_dispatch_table_for_class(self); 21 | return 0; 22 | } 23 | } 24 | NSLog(@"Looking in next list"); 25 | methods = methods->method_next; 26 | } 27 | return -1; 28 | } 29 | + (int) addMethod:(IMP)aMethod forSelectorNamed:(char*)aSelector 30 | { 31 | MethodList_t methods = ((Class)self)->methods; 32 | //Find the last method list 33 | while(methods->method_next != NULL) 34 | { 35 | methods = methods->method_next; 36 | } 37 | methods->method_next = calloc(sizeof(struct objc_method_list), 1); 38 | methods->method_next->method_count = 1; 39 | Method_t method = &methods->method_next->method_list[0]; 40 | method->method_name = sel_register_name(aSelector); 41 | method->method_types = NULL; 42 | method->method_imp = aMethod; 43 | __objc_update_dispatch_table_for_class(self); 44 | return 0; 45 | } 46 | @end 47 | -------------------------------------------------------------------------------- /Compiler/old/README: -------------------------------------------------------------------------------- 1 | This directory contains things that are related to old approaches and not used, 2 | but which might be useful again in the future. It will be removed at some 3 | point. 4 | -------------------------------------------------------------------------------- /Compiler/old/StringMap.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | *

Simple hash function used to using C strings as keys in NSMapTables. 5 | * Simply takes the first few bytes of the string as an int

6 | */ 7 | unsigned simpleStringHash(NSMapTable *table, const void *anObject); 8 | /** 9 | *

Wrapper around strcmp for use in NSMapTables.

10 | */ 11 | BOOL isCStringEqual(NSMapTable *table, const void * str1, const void * str2); 12 | 13 | /** 14 | * Set of callbacks for defining a simple string-keyed map. 15 | */ 16 | static const NSMapTableKeyCallBacks STRING_MAP_KEY_CALLBACKS = {simpleStringHash, isCStringEqual, NULL, NULL, NULL, NSNotAnIntMapKey}; 17 | -------------------------------------------------------------------------------- /Compiler/old/StringMap.m: -------------------------------------------------------------------------------- 1 | #import "StringMap.h" 2 | 3 | /** 4 | * A trivial hash from a string, made by casting the first few characters of a 5 | * string to an integer. 6 | */ 7 | unsigned simpleStringHash(NSMapTable *table, const void *anObject) 8 | { 9 | int len = strlen(anObject) + 1; 10 | if(len >= sizeof(unsigned)) 11 | { 12 | return *(unsigned *)anObject; 13 | } 14 | if(len >= sizeof(unsigned short)) 15 | { 16 | return (unsigned)*(unsigned short*)anObject; 17 | } 18 | if(len >= sizeof(unsigned char)) 19 | { 20 | return (unsigned)*(unsigned char*)anObject; 21 | } 22 | //Should never be reached 23 | return 0; 24 | } 25 | /** 26 | * String comparison function. Simple wrapper around strcmp. 27 | */ 28 | BOOL isCStringEqual(NSMapTable *table, const void * str1, const void * str2) 29 | { 30 | return strcmp(str1, str2) == 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Compiler/old/main.m: -------------------------------------------------------------------------------- 1 | #include 2 | #import "SymbolTable.h" 3 | #import "Parser.h" 4 | 5 | 6 | int main(void) 7 | { 8 | [NSAutoreleasePool new]; 9 | Parser * p = [[Parser alloc] initWithClass:[Test class]]; 10 | [[p parseString: @"doStuff | a b c| \na bar: [ :x | b do:c.].\nb := fish eat:banana with:mouth.\n foo bar:wibble fish:banana."] print]; 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /Compiler/old/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARSER_H_INCLUDED__ 2 | #define __PARSER_H_INCLUDED__ 3 | typedef struct _Expression Expression; 4 | 5 | typedef struct _Argument 6 | { 7 | char * selector_component; 8 | Expression * value; 9 | struct _Argument * next; 10 | } Argument; 11 | 12 | typedef struct 13 | { 14 | char * target; 15 | Argument * arguments; 16 | int temps; 17 | } Message; 18 | 19 | struct _Expression 20 | { 21 | enum {message, variable} type; 22 | union 23 | { 24 | Message * message; 25 | char * variable; 26 | } value; 27 | }; 28 | 29 | typedef struct 30 | { 31 | char * target; 32 | Expression * value; 33 | } Assignment; 34 | 35 | typedef struct _Statement 36 | { 37 | enum {assignment, message_pass} type; 38 | union 39 | { 40 | Assignment * assignment; 41 | Message * message; 42 | } value; 43 | struct _Statement * next; 44 | } Statement; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /Compiler/old/smalltalk.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "parser.h" 3 | #include "y.tab.h" 4 | #include 5 | #define YY_NO_UNPUT 6 | #define RETURN_STRING(x) {/*printf("Found word: %s\n", yytext);*/yylval.stringValue = strdup(yytext); return x;} 7 | %} 8 | %option noyywrap 9 | 10 | WORD [a-zA-Z_]+[a-zA-Z0-9_]* 11 | NUMBER [0-9]+ 12 | WHITE [ \n \t]+ 13 | %% 14 | {WHITE} /* Skip Whitespace */ 15 | {WORD} RETURN_STRING(WORD) 16 | {NUMBER}RETURN_STRING(NUMBER) 17 | . { return (int) yytext[0]; } 18 | %% 19 | void yyerror(char *s) 20 | { 21 | fprintf(stderr, "%s\n", s); 22 | } 23 | -------------------------------------------------------------------------------- /Compiler/old/smalltalk.yacc: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "parser.h" 4 | #define YY_MAIN 0 5 | void collect_local(char *); 6 | %} 7 | %union 8 | { 9 | char* stringValue; 10 | Message * message; 11 | Statement * statement; 12 | Argument * argument; 13 | Expression * expression; 14 | } 15 | %token WORD 16 | %type message_send 17 | %type message message_with_arguments; 18 | %type statement 19 | %type expression; 20 | 21 | //%type message_send message message_with_arguments 22 | %% 23 | method: 24 | local_list statement_list; 25 | 26 | local_list: 27 | '|' locals '|' 28 | | 29 | ; 30 | 31 | locals: 32 | WORD locals 33 | { 34 | collect_local($1); 35 | } 36 | | 37 | ; 38 | 39 | statement_list: 40 | statement_list statement '.' 41 | { 42 | addStatement($2); 43 | } 44 | | 45 | ; 46 | 47 | statement: 48 | message_send 49 | { 50 | $$ = malloc(sizeof(Statement)); 51 | $$->type = message_pass; 52 | $$->value.message = $1; 53 | } 54 | | 55 | assignment 56 | { 57 | //Assignments not supported yet 58 | $$ = NULL; 59 | }; 60 | 61 | message_send: 62 | WORD message 63 | { 64 | $$ = malloc(sizeof(Message)); 65 | $$->target = $1; 66 | $$->arguments = $2; 67 | }; 68 | 69 | message: 70 | WORD 71 | { 72 | $$ = malloc(sizeof(Argument)); 73 | $$->selector_component = $1; 74 | $$->value = NULL; 75 | $$->next = NULL; 76 | } 77 | | 78 | message_with_arguments 79 | { 80 | $$ = $1; 81 | } 82 | ; 83 | 84 | message_with_arguments: 85 | WORD ':' expression message_with_arguments 86 | { 87 | $$ = malloc(sizeof(Argument)); 88 | $$->selector_component = $1; 89 | $$->value = $3; 90 | $$->next = $4; 91 | } 92 | | 93 | { $$ = NULL; } 94 | ; 95 | 96 | assignment: 97 | WORD ':' '=' expression ; 98 | 99 | expression: 100 | WORD 101 | { 102 | $$ = malloc(sizeof(Expression)); 103 | $$->type = variable; 104 | $$->value.variable = $1; 105 | } 106 | ; 107 | %% 108 | int parseSmalltalk(char * program) 109 | { 110 | //yy_scan_string("| a b c | \n foo bar."); 111 | yy_scan_string(program); 112 | return yyparse(); 113 | } 114 | -------------------------------------------------------------------------------- /EScript/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007, David Chisnall 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | * Neither the name of the Étoilé project, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | 16 | 17 | -------------------------------------------------------------------------------- /EScript/EScriptCompiler.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EScriptCompiler : LKCompiler {} 4 | @end 5 | -------------------------------------------------------------------------------- /EScript/EScriptCompiler.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EScriptCompiler.h" 3 | #import "EScriptParser.h" 4 | 5 | @implementation EScriptCompiler 6 | + (NSString*) languageName 7 | { 8 | return @"EScript"; 9 | } 10 | + (NSString*) fileExtension 11 | { 12 | return @"escript"; 13 | } 14 | + (Class) parserClass 15 | { 16 | return [EScriptParser class]; 17 | } 18 | @end 19 | -------------------------------------------------------------------------------- /EScript/EScriptObject.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EScriptObject : NSObject {} 4 | - (id) construct; 5 | @end 6 | -------------------------------------------------------------------------------- /EScript/EScriptObject.m: -------------------------------------------------------------------------------- 1 | #import "EScriptObject.h" 2 | #import 3 | #import 4 | 5 | @implementation EScriptObject 6 | - (id) construct 7 | { 8 | return self; 9 | } 10 | @end 11 | @interface _NSBlock : NSObject 12 | - (id)value; 13 | @end 14 | 15 | @implementation _NSBlock (EScript) 16 | - (id)construct 17 | { 18 | id prototype = [[self slotValueForKey: @"prototype"] clone]; 19 | if (nil == prototype) 20 | { 21 | prototype = [EScriptObject new]; 22 | } 23 | [self setValue: prototype forKey: @"this"]; 24 | [self value]; 25 | [self setValue: nil forKey: @"this"]; 26 | return [prototype autorelease]; 27 | } 28 | @end 29 | 30 | @implementation NSObject (EScript) 31 | + (id)construct 32 | { 33 | return [[[self alloc] init] autorelease]; 34 | } 35 | - (id)value 36 | { 37 | return self; 38 | } 39 | @end 40 | -------------------------------------------------------------------------------- /EScript/EScriptParser.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class LKAST; 4 | @protocol LKParser; 5 | 6 | /** 7 | * EScript parser class. This class implements a tokeniser and calls a 8 | * parser created using the Lemon parser generator. 9 | */ 10 | @interface EScriptParser : NSObject { 11 | LKAST *ast; 12 | } 13 | /** 14 | * Used by the Lemon implementation to feed the generated AST back so the 15 | * Parser can return it. 16 | */ 17 | - (void) setAST:(LKAST*)ast; 18 | @end 19 | -------------------------------------------------------------------------------- /EScript/EScriptPreamble.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EScriptPreamble : LKAST {} 4 | + (id) preamble; 5 | @end 6 | -------------------------------------------------------------------------------- /EScript/EScriptPreamble.m: -------------------------------------------------------------------------------- 1 | #import "EScriptPreamble.h" 2 | #import 3 | #import 4 | #import "EScriptObject.h" 5 | 6 | 7 | @implementation EScriptPreamble 8 | + (id) preamble 9 | { 10 | return AUTORELEASE([[self alloc] init]); 11 | } 12 | 13 | - (BOOL)check 14 | { 15 | return YES; 16 | } 17 | 18 | - (NSString*) description 19 | { 20 | return @"EScript Preamble"; 21 | } 22 | 23 | - (void*) compileWithGenerator:(id)aGenerator 24 | { 25 | NSLog(@"Compiling"); 26 | id module = [self module]; 27 | NSArray *types_new = [module typesForMethod:@"new"]; 28 | 29 | id res; 30 | [symbols addSymbolsNamed: A(@"Object", @"Array") ofKind: LKSymbolScopeClass]; 31 | res = [aGenerator loadClassNamed: @"EScriptObject"]; 32 | res = [aGenerator sendMessage: @"new" 33 | types: types_new 34 | toObject: res 35 | withArgs: NULL 36 | count: 0]; 37 | [aGenerator storeValue: res inVariable: [symbols symbolForName: @"Object"]]; 38 | res = [aGenerator loadClassNamed: @"NSMutableArray"]; 39 | res = [aGenerator sendMessage: @"new" 40 | types: types_new 41 | toObject: res 42 | withArgs: NULL 43 | count: 0]; 44 | [aGenerator storeValue: res inVariable: [symbols symbolForName: @"Array"]]; 45 | NSLog(@"wrote preamble"); 46 | 47 | return NULL; 48 | } 49 | - (id)interpretInContext: (LKInterpreterContext*)context 50 | { 51 | id o = [EScriptObject new]; 52 | [context setValue: o 53 | forSymbol: @"Object"]; 54 | o = [NSMutableArray new]; 55 | [context setValue: o 56 | forSymbol: @"Array"]; 57 | return nil; 58 | } 59 | @end 60 | -------------------------------------------------------------------------------- /EScript/EScriptTransform.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EScriptHoistIvars : LKASTVisitor @end 4 | @interface EScriptHiddenClassTransform : LKASTVisitor 5 | { 6 | NSMutableDictionary *newClasses; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /EScript/EScriptTransform.m: -------------------------------------------------------------------------------- 1 | #import "EScriptTransform.h" 2 | 3 | @implementation EScriptHoistIvars 4 | - (id)visitVariableDecl: (LKVariableDecl*)decl 5 | { 6 | LKMethod *method = (LKMethod*)[decl parent]; 7 | LKSubclass *cls = (LKSubclass*)[method parent]; 8 | // Make sure that this is a decl in a method. 9 | if (![cls isKindOfClass: [LKSubclass class]]) 10 | { 11 | return decl; 12 | } 13 | NSString * name = [decl name]; 14 | 15 | [[[method symbols] symbols] removeObject: name]; 16 | [cls addInstanceVariable: name]; 17 | return nil; 18 | } 19 | @end 20 | 21 | @implementation EScriptHiddenClassTransform 22 | - (id)init 23 | { 24 | SUPERINIT; 25 | newClasses = [NSMutableDictionary new]; 26 | return self; 27 | } 28 | - (void)dealloc 29 | { 30 | [newClasses release]; 31 | [super dealloc]; 32 | } 33 | #define EXPECT_CLASS(x, cls) \ 34 | if (![(x) isKindOfClass: [cls class]])\ 35 | {\ 36 | return msg;\ 37 | } 38 | - (id)visitMessageSend: (LKMessageSend*)msg 39 | { 40 | // Check that this message is setting a slot 41 | if (![@"setValue:forKey:" isEqualToString: [msg selector]]) 42 | { 43 | return msg; 44 | } 45 | NSArray *args = [msg arguments]; 46 | // Check that we are setting a constant string key 47 | EXPECT_CLASS([args objectAtIndex: 1], LKStringLiteral); 48 | NSString *className = [[args objectAtIndex: 1] stringValue]; 49 | EXPECT_CLASS([msg parent], LKBlockExpr); 50 | EXPECT_CLASS([[msg parent] parent], LKAssignExpr); 51 | // If the value being assigned is a block, then this is a method. If not, 52 | // then it is an ivar. If it's a method, then it is also an ivar 53 | // containing the block, just to confuse matters. 54 | BOOL isMethod = 55 | [[[msg arguments] objectAtIndex: 0] isKindOfClass: [LKBlockExpr class]]; 56 | 57 | NSLog(@"Parent: %@", [[msg parent] class]); 58 | NSLog(@"Parent parent: %@", [[[msg parent] parent] class]); 59 | LKSubclass *cls = [newClasses objectForKey: className]; 60 | if (nil == cls) 61 | { 62 | cls = [LKSubclass subclassWithName: className 63 | superclassNamed: @"EScriptObject" 64 | cvars: nil 65 | ivars: nil 66 | methods: nil]; 67 | [newClasses setObject: cls forKey: className]; 68 | } 69 | 70 | return msg; 71 | } 72 | @end 73 | -------------------------------------------------------------------------------- /EScript/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | 7 | VERSION = 0.1 8 | BUNDLE_NAME = EScript 9 | BUNDLE_EXTENSION = .language 10 | BUNDLE_INSTALL_DIR = $(GNUSTEP_BUNDLES)/LanguageKit 11 | 12 | ${BUNDLE_NAME}_PRINCIPAL_CLASS = EScriptCompiler 13 | 14 | ${BUNDLE_NAME}_OBJC_FILES = \ 15 | escript.m\ 16 | EScriptCompiler.m\ 17 | EScriptObject.m\ 18 | EScriptParser.m\ 19 | EScriptPreamble.m\ 20 | EScriptTransform.m 21 | 22 | ${BUNDLE_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 23 | ${BUNDLE_NAME}_LDFLAGS += -g -lEtoileFoundation -lLanguageKit 24 | ${BUNDLE_NAME}_CFLAGS += -Wno-implicit -g 25 | 26 | include $(GNUSTEP_MAKEFILES)/bundle.make 27 | -include ../../etoile.make 28 | 29 | escript.m: escript.y lempar.c lemon 30 | @echo Generating parser... 31 | @./lemon escript.y ; mv escript.c escript.m 32 | 33 | lemon: lemon.c 34 | @echo Compiling parser generator 35 | @$(CC) lemon.c -o lemon 36 | 37 | clean:: 38 | @rm -f escript.h escript.m escript.out 39 | -------------------------------------------------------------------------------- /EScript/README: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | EtoileScript is a dialect of ECMAScript for the Étoilé environment. It is not 5 | intended as being a full ECMAScript environment, but rather as a demonstration 6 | of the ability for LanguageKit to support differing languages. 7 | 8 | -------------------------------------------------------------------------------- /EScript/test.escript: -------------------------------------------------------------------------------- 1 | var a = new Object(); 2 | 'Sending a message to a constant NSString'.log(); 3 | var n = 12; 4 | n += 22; 5 | ETTranscript.show(n); 6 | ETTranscript.cr(); 7 | 8 | for (var i=0 ; i < 10 ; i++) 9 | { 10 | ETTranscript.show(i); 11 | ETTranscript.cr(); 12 | } 13 | 14 | function Test() 15 | { 16 | ETTranscript.show('Running Test() function'); 17 | ETTranscript.cr(); 18 | this.log(); 19 | this.print = 20 | function() 21 | { 22 | ETTranscript.show('Running a method in an object constructed from EScript'); 23 | ETTranscript.cr(); 24 | }; 25 | } 26 | var t = new Test(); 27 | 'Test returned new object'.log(); 28 | t.log(); 29 | t.print(); 30 | 31 | var nsobj = new NSObject(); 32 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME = Languages 2 | 3 | include $(GNUSTEP_MAKEFILES)/common.make 4 | 5 | # 6 | # Variables to turn projects on and off in the build process 7 | # (listed by alphabetical order) 8 | # 9 | 10 | -include ../modules.make 11 | 12 | export smalltalk ?= yes 13 | 14 | # 15 | # Projects (listed by dependency order, then alphabetical order) 16 | # 17 | SUBPROJECTS += SourceCodeKit 18 | 19 | ifeq ($(smalltalk), yes) 20 | SUBPROJECTS += LanguageKit 21 | SUBPROJECTS += Smalltalk 22 | SUBPROJECTS += Compiler 23 | SUBPROJECTS += LKPlugins 24 | endif 25 | 26 | include $(GNUSTEP_MAKEFILES)/aggregate.make 27 | -------------------------------------------------------------------------------- /LKPlugins/CommentsToLogs/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | 7 | VERSION = 1.0 8 | BUNDLE_NAME = CommentToLog 9 | BUNDLE_EXTENSION = .ast 10 | BUNDLE_INSTALL_DIR = $(GNUSTEP_BUNDLES)/LanguageKit 11 | 12 | ${BUNDLE_NAME}_PRINCIPAL_CLASS = LKCommentToLogTransform 13 | 14 | ${BUNDLE_NAME}_OBJC_FILES = \ 15 | transform.m 16 | 17 | ${BUNDLE_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 18 | ${BUNDLE_NAME}_LDFLAGS += -g -lEtoileFoundation -lLanguageKit 19 | ${BUNDLE_NAME}_CFLAGS += -Wno-implicit -g 20 | 21 | include $(GNUSTEP_MAKEFILES)/bundle.make 22 | -include ../../../etoile.make 23 | 24 | -------------------------------------------------------------------------------- /LKPlugins/CommentsToLogs/transform.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKCommentToLogTransform : LKASTVisitor 4 | @end 5 | @implementation LKCommentToLogTransform 6 | - (LKAST*) visitComment:(LKComment*)aNode 7 | { 8 | LKMessageSend* msg = [LKMessageSend messageWithSelectorName: @"log"]; 9 | NSString *string = [aNode stringValue]; 10 | string = [@"Comment: " stringByAppendingString:string]; 11 | [msg setTarget: [LKStringLiteral literalFromString:string]]; 12 | [msg setParent: [aNode parent]]; 13 | [msg check]; 14 | return msg; 15 | } 16 | @end 17 | -------------------------------------------------------------------------------- /LKPlugins/GNUmakefile: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME = LKPlugins 2 | 3 | include $(GNUSTEP_MAKEFILES)/common.make 4 | 5 | # 6 | # Variables to turn projects on and off in the build process 7 | # (listed by alphabetical order) 8 | # 9 | 10 | -include ../../modules.make 11 | 12 | export commentsToLogs ?= yes 13 | 14 | # 15 | # Projects (listed by dependency order, then alphabetical order) 16 | # 17 | 18 | ifeq ($(commentsToLogs), yes) 19 | SUBPROJECTS += CommentsToLogs 20 | SUBPROJECTS += LowerIfTrue 21 | SUBPROJECTS += LowerIfResponds 22 | endif 23 | 24 | include $(GNUSTEP_MAKEFILES)/aggregate.make 25 | -------------------------------------------------------------------------------- /LKPlugins/LowerIfResponds/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | 7 | VERSION = 1.0 8 | BUNDLE_NAME = LowerIfResponds 9 | BUNDLE_EXTENSION = .ast 10 | BUNDLE_INSTALL_DIR = $(GNUSTEP_BUNDLES)/LanguageKit 11 | 12 | ${BUNDLE_NAME}_PRINCIPAL_CLASS = LKLowerIfRespondsTransform 13 | 14 | ${BUNDLE_NAME}_OBJC_FILES = \ 15 | transform.m 16 | 17 | ${BUNDLE_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 18 | ${BUNDLE_NAME}_LDFLAGS += -g -lEtoileFoundation -lLanguageKit 19 | ${BUNDLE_NAME}_CFLAGS += -Wno-implicit -g 20 | 21 | include $(GNUSTEP_MAKEFILES)/bundle.make 22 | -include ../../../etoile.make 23 | 24 | -------------------------------------------------------------------------------- /LKPlugins/LowerIfResponds/transform.m: -------------------------------------------------------------------------------- 1 | #import 2 | /** 3 | * Transforms: 4 | * [[foo ifResponds] bar]; 5 | * To: 6 | * if ([foo respondsToSelector: bar]) [foo bar]; 7 | */ 8 | @interface LKLowerIfRespondsTransform : LKASTVisitor 9 | @end 10 | @implementation LKLowerIfRespondsTransform 11 | - (LKAST*)visitMessageSend: (LKMessageSend*)aNode 12 | { 13 | LKAST *receiver = [aNode target]; 14 | if (![receiver isKindOfClass: [LKMessageSend class]]) 15 | { 16 | return aNode; 17 | } 18 | 19 | LKMessageSend *msgSend = (LKMessageSend*)receiver; 20 | if (![@"ifResponds" isEqualToString: [msgSend selector]]) 21 | { 22 | return aNode; 23 | } 24 | 25 | receiver = [msgSend target]; 26 | // Don't run the transform on message send intermediates, or we get some 27 | // double-evaluation. This ideally needs fixing in LK to allow 28 | // intermediates to be reused. 29 | if ([receiver isKindOfClass: [LKMessageSend class]]) 30 | { 31 | return aNode; 32 | } 33 | 34 | LKMessageSend *condition = 35 | [LKMessageSend messageWithSelectorName: @"respondsToSelector:"]; 36 | [condition setTarget: receiver]; 37 | [condition addArgument: [LKSymbolRef referenceWithSymbol: [aNode selector]]]; 38 | 39 | [aNode setTarget: receiver]; 40 | 41 | LKIfStatement *ifStatement = 42 | [LKIfStatement ifStatementWithCondition: condition 43 | then: A(aNode) 44 | else: [NSArray array]]; 45 | 46 | [ifStatement setParent: [aNode parent]]; 47 | [ifStatement check]; 48 | return ifStatement; 49 | } 50 | @end 51 | -------------------------------------------------------------------------------- /LKPlugins/LowerIfTrue/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | 7 | VERSION = 1.0 8 | BUNDLE_NAME = LowerIfTrue 9 | BUNDLE_EXTENSION = .ast 10 | BUNDLE_INSTALL_DIR = $(GNUSTEP_BUNDLES)/LanguageKit 11 | 12 | ${BUNDLE_NAME}_PRINCIPAL_CLASS = LKLowerIfTrueTransform 13 | 14 | ${BUNDLE_NAME}_OBJC_FILES = \ 15 | transform.m 16 | 17 | ${BUNDLE_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 18 | ${BUNDLE_NAME}_LDFLAGS += -g -lEtoileFoundation -lLanguageKit 19 | ${BUNDLE_NAME}_CFLAGS += -Wno-implicit -g 20 | 21 | include $(GNUSTEP_MAKEFILES)/bundle.make 22 | -include ../../../etoile.make 23 | 24 | -------------------------------------------------------------------------------- /LKPlugins/LowerIfTrue/transform.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | NSArray *statementsFromBlock(LKAST*aBlock) 5 | { 6 | if ([aBlock isKindOfClass: [LKBlockExpr class]]) 7 | { 8 | LKBlockExpr *blockExpr = (LKBlockExpr*)aBlock; 9 | return [[[blockExpr statements] copy] autorelease]; 10 | } 11 | LKMessageSend *valueMsg = [LKMessageSend messageWithSelectorName: @"value"]; 12 | [valueMsg setTarget: aBlock]; 13 | return A(valueMsg); 14 | } 15 | @interface LKCollectExternalRefs : LKASTVisitor 16 | { 17 | @public 18 | NSMutableSet *refs; 19 | } 20 | @end 21 | @implementation LKCollectExternalRefs 22 | - (LKAST*)visitDeclRef: (LKDeclRef*)aDeclRef 23 | { 24 | [refs addObject: [[aDeclRef symbol] stringValue]]; 25 | return aDeclRef; 26 | } 27 | @end 28 | 29 | @interface LKLowerIfTrueTransform : LKASTVisitor 30 | @end 31 | @implementation LKLowerIfTrueTransform 32 | - (LKAST*) visitMessageSend:(LKMessageSend*)aNode 33 | { 34 | LKBlockExpr *thenBlock = nil; 35 | LKBlockExpr *elseBlock = nil; 36 | if ([@"ifTrue:ifFalse:" isEqualToString:[aNode selector]]) 37 | { 38 | NSArray *args = [aNode arguments]; 39 | thenBlock = [args objectAtIndex:0]; 40 | elseBlock = [args objectAtIndex:1]; 41 | } 42 | else if ([@"ifTrue:" isEqualToString:[aNode selector]]) 43 | { 44 | NSArray *args = [aNode arguments]; 45 | thenBlock = [args objectAtIndex:0]; 46 | } 47 | else if ([@"ifFalse:" isEqualToString:[aNode selector]]) 48 | { 49 | NSArray *args = [aNode arguments]; 50 | elseBlock = [args objectAtIndex:0]; 51 | } 52 | else 53 | { 54 | return aNode; 55 | } 56 | 57 | // Remove references to symbols from the blocks we're deleting 58 | LKCollectExternalRefs *exts = [LKCollectExternalRefs new]; 59 | LKSymbolTable *symTab = [aNode symbols]; 60 | NSMutableSet *refs = [NSMutableSet new]; 61 | exts->refs = refs; 62 | [thenBlock visitWithVisitor: exts]; 63 | for (NSString *sym in refs) 64 | { 65 | LKSymbol *s = [symTab symbolForName: sym]; 66 | s.referencingScopes--; 67 | } 68 | [refs removeAllObjects]; 69 | [elseBlock visitWithVisitor: exts]; 70 | for (NSString *sym in refs) 71 | { 72 | LKSymbol *s = [symTab symbolForName: sym]; 73 | s.referencingScopes--; 74 | } 75 | [refs release]; 76 | [exts release]; 77 | 78 | NSArray *thenClause = statementsFromBlock(thenBlock); 79 | NSArray *elseClause = statementsFromBlock(elseBlock); 80 | LKAST *receiver = [aNode target]; 81 | LKMessageSend *condition = 82 | [LKMessageSend messageWithSelectorName: @"boolValue"]; 83 | [condition setTarget: receiver]; 84 | 85 | LKIfStatement *ifStatement = 86 | [LKIfStatement ifStatementWithCondition: receiver //condition 87 | then: thenClause 88 | else: elseClause]; 89 | 90 | [ifStatement setParent: [aNode parent]]; 91 | [ifStatement check]; 92 | return ifStatement; 93 | } 94 | @end 95 | -------------------------------------------------------------------------------- /LanguageKit/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007, David Chisnall 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/ABI.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ABI.h defines three constants for each target architecture which define the 3 | * calling convention for returning structures from functions. These are: 4 | * 5 | * MAX_INTS_IN_REGISTERS - This defines the maximum number of integers in a 6 | * structure that can be returned in registers. 7 | * 8 | * MAX_FLOATS_IN_REGISTERS - This defines the maximum number of floating point 9 | * values in a structure that can be returned in registers. 10 | * 11 | * PASS_STRUCTS_AS_POINTER - Flag indicating that structures are always passed 12 | * by reference. 13 | * 14 | * Any structure with more elements than this will be returned on the stack. 15 | * The final value, SMALL_FLOAT_STRUCTS_ON_STACK, is a flag which indicates 16 | * whether small structures (e.g. NSPoint) should be returned in integer 17 | * registers. This is the case on FreeBSD/i386, for example. 18 | */ 19 | // These are different for x86-64, but I don't know what they should be. 20 | #ifdef __i386__ 21 | # ifdef __FreeBSD__ 22 | static const unsigned MAX_INTS_IN_REGISTERS = 2; 23 | static const unsigned MAX_FLOATS_IN_REGISTERS = 0; 24 | static const bool SMALL_FLOAT_STRUCTS_ON_STACK = true; 25 | # elif defined(__linux__) 26 | static const unsigned MAX_INTS_IN_REGISTERS = 0; 27 | static const unsigned MAX_FLOATS_IN_REGISTERS = 0; 28 | static const bool SMALL_FLOAT_STRUCTS_ON_STACK = false; 29 | # endif 30 | #elif defined(__amd64__) 31 | static const unsigned MAX_INTS_IN_REGISTERS = 6; 32 | static const unsigned MAX_FLOATS_IN_REGISTERS = 8; 33 | static const bool SMALL_FLOAT_STRUCTS_ON_STACK = false; 34 | #else 35 | # ifdef __FreeBSD__ 36 | static const unsigned MAX_INTS_IN_REGISTERS = 2; 37 | # else 38 | // Some placeholder values 39 | static const unsigned MAX_INTS_IN_REGISTERS = 0; 40 | # endif 41 | static const unsigned MAX_FLOATS_IN_REGISTERS = 0; 42 | static const bool SMALL_FLOAT_STRUCTS_ON_STACK = true; 43 | #endif 44 | 45 | #if defined(__linux__) && defined(__PPC__) 46 | static const bool PASS_STRUCTS_AS_POINTER = 1; 47 | #else 48 | static const bool PASS_STRUCTS_AS_POINTER = 0; 49 | #endif 50 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/CodeGenBlock.h: -------------------------------------------------------------------------------- 1 | #include "llvm/ADT/SmallVector.h" 2 | #include "CodeGenModule.h" 3 | #include "CodeGenLexicalScope.h" 4 | 5 | namespace llvm { 6 | class BasicBlock; 7 | class Function; 8 | class Module; 9 | class Type; 10 | class Value; 11 | class StructureType; 12 | class FunctionType; 13 | } 14 | 15 | namespace etoile 16 | { 17 | namespace languagekit 18 | { 19 | 20 | class CodeGenModule; 21 | 22 | /** 23 | * Class responsible for emitting blocks. The outer scope is responsible for 24 | * generating any block byref structures for bound arguments, this will 25 | * generate the types for the block and 26 | */ 27 | class CodeGenBlock : public CodeGenSubroutine { 28 | /** 29 | * The type of this block's structure. 30 | */ 31 | LLVMStructTy *blockStructureTy; 32 | /** 33 | * A pointer to the block object, in its own scope. 34 | */ 35 | llvm::Value *blockContext; 36 | /** 37 | * A pointer to the block object, in the parent's scope. 38 | */ 39 | llvm::Instruction *block; 40 | /** 41 | * Emits the descriptor for this block. The descriptor contains the block 42 | * type encoding, along with the functions required to copy and dispose of 43 | * the block. 44 | */ 45 | llvm::Constant* emitBlockDescriptor(NSString *signature, 46 | llvm::StructType *blockType); 47 | public: 48 | virtual void SetReturn(Value* RetVal); 49 | /** 50 | * Returns the block's object. 51 | */ 52 | virtual llvm::Value *LoadBlockContext(void); 53 | 54 | /** 55 | * Begins generating a block. The arguments and locals contain an array of 56 | * LKSymbol objects representing the local and argument values in this 57 | * block. Bound variables are passed in when the block is created. 58 | */ 59 | CodeGenBlock(NSArray *locals, 60 | NSArray *arguments, 61 | NSArray *bound, 62 | NSString *signature, 63 | CodeGenModule *Mod); 64 | 65 | void SetBlockReturn(llvm::Value* RetVal); 66 | 67 | /** 68 | * Creates an on-stack instance of the block, with all of the bound 69 | * variables attached. 70 | */ 71 | llvm::Value *EndBlock(void); 72 | }; 73 | }} 74 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/CodeGenHelpers.mm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/etoile/Languages/068ed397496a4e445ff9af7b56e2c60a0126d783/LanguageKit/CodeGen/CodeGenHelpers.mm -------------------------------------------------------------------------------- /LanguageKit/CodeGen/CodeGenTypes.h: -------------------------------------------------------------------------------- 1 | #import "LLVMCompat.h" 2 | #import "ABIInfo.h" 3 | @class NSString; 4 | namespace llvm 5 | { 6 | class Module; 7 | class PointerType; 8 | class IntegerType; 9 | } 10 | 11 | namespace etoile 12 | { 13 | namespace languagekit 14 | { 15 | struct CodeGenTypes 16 | { 17 | llvm::Module &Mod; 18 | /** 19 | * ABI Information provider. 20 | */ 21 | ABIInfo *AI; 22 | /** 23 | * LLVM void type. 24 | */ 25 | LLVMType *voidTy; 26 | /** 27 | * Type used for object pointers. 28 | */ 29 | LLVMPointerTy *idTy; 30 | /** 31 | * Pointer to something. 32 | */ 33 | LLVMPointerTy *ptrToVoidTy; 34 | /** 35 | * Type used for pointers to object pointers. 36 | */ 37 | LLVMPointerTy *ptrToIdTy; 38 | /** 39 | * Type used for selectors. 40 | */ 41 | LLVMPointerTy *selTy; 42 | /** 43 | * LLVM type for C char. 44 | */ 45 | LLVMIntegerTy *charTy; 46 | /** 47 | * LLVM type for C short. 48 | */ 49 | LLVMIntegerTy *shortTy; 50 | /** 51 | * LLVM type for C int. 52 | */ 53 | LLVMIntegerTy *intTy; 54 | /** 55 | * LLVM type for C long. 56 | */ 57 | LLVMIntegerTy *longTy; 58 | /** 59 | * LLVM type for C long long. 60 | */ 61 | LLVMIntegerTy *longLongTy; 62 | /** 63 | * Type of pointer-sized integers. 64 | */ 65 | LLVMIntegerTy *intPtrTy; 66 | /** 67 | * Type for pointer subtraction results. 68 | */ 69 | LLVMIntegerTy *ptrDiffTy; 70 | /** 71 | * The type for a byref structure. 72 | */ 73 | LLVMStructTy *genericByRefType; 74 | /** 75 | * Some zeros to reuse. 76 | */ 77 | llvm::Value *zeros[2]; 78 | CodeGenTypes(llvm::Module &M); 79 | /** 80 | * Returns a function type for the specified Objective-C type encoding. 81 | */ 82 | llvm::FunctionType* functionTypeFromString(NSString *typestr, 83 | bool &isSRet, 84 | LLVMType *&realRetTy); 85 | /** 86 | * Returns a type encoding for the first value in the specified type 87 | * encoding. For example, @:@ will return the type encoding for @ 88 | * (id), not a function type. 89 | */ 90 | LLVMType *typeFromString(NSString *typeEncoding); 91 | 92 | /** 93 | * Indicates that the current value is a block. If we pass it to a 94 | * function or a method, or store it on the heap or in a global, then we 95 | * need to call objc_retainBlock(). 96 | */ 97 | unsigned int valueIsBlock; 98 | llvm::MDNode *valueIsBlockNode; 99 | }; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | # We redefine the project name since the framework name doesn't match the name 7 | # of the project directory (CodeGen) 8 | PROJECT_NAME = LanguageKitCodeGen 9 | 10 | VERSION = 0.6 11 | FRAMEWORK_NAME = ${PROJECT_NAME} 12 | 13 | 14 | ifeq ($(GNUSTEP_TARGET_CPU), x86_64) 15 | ${FRAMEWORK_NAME}_OBJCC_FILES += \ 16 | AMD64/AMD64ABIInfo.mm 17 | endif 18 | 19 | ${FRAMEWORK_NAME}_OBJCC_FILES += \ 20 | GenericABIInfo.mm\ 21 | CGObjCGNU.mm\ 22 | CodeGenAssignments.mm\ 23 | CodeGenBlock.mm\ 24 | CodeGenHelpers.mm\ 25 | CodeGenLexicalScope.mm\ 26 | CodeGenModule.mm\ 27 | CodeGenTypes.mm\ 28 | LKCompiler+JTL.mm\ 29 | LLVMCodeGen.mm 30 | 31 | ${FRAMEWORK_NAME}_HEADER_FILES = \ 32 | CodeGenBlock.h\ 33 | CodeGenModule.h 34 | 35 | # uncomment this line when debugging if you have problems with over-aggressive 36 | # inlining throwing away useful debugging info. 37 | #${FRAMEWORK_NAME}_CXXFLAGS = -fno-inline 38 | #${FRAMEWORK_NAME}_OBJCCFLAGS = -fno-inline 39 | ${FRAMEWORK_NAME}_CPPFLAGS += -D_GNU_SOURCE 40 | ${FRAMEWORK_NAME}_OBJCFLAGS += -std=c99 -g -Wno-unused-value -fexceptions -fobjc-arc 41 | ${FRAMEWORK_NAME}_OBJCCFLAGS += -std=c++11 -Wno-variadic-macros -Wno-gnu -Wno-pedantic 42 | ${FRAMEWORK_NAME}_LDFLAGS += -g 43 | ${FRAMEWORK_NAME}_CFLAGS += -Wno-implicit -g 44 | 45 | # LLVM doesn't provide its version in any header files, so define it here using 46 | # some ugly sed tricks to parse the output from llvm-config 47 | ${FRAMEWORK_NAME}_CPPFLAGS = $(shell llvm-config --version | sed 's/\([0-9]*\).\([0-9]*\).*/-DLLVM_MAJOR=\1 -DLLVM_MINOR=\2/') 48 | 49 | # LLVM flags 50 | LLVM_LIBS=analysis archive bitreader bitwriter codegen core engine executionengine instrumentation interpreter ipa ipo jit linker native nativecodegen scalaropts selectiondag support target transformutils #x86 x86asmprinter x86codegen 51 | #LLVM_LIBS=all 52 | 53 | ${FRAMEWORK_NAME}_CCFLAGS += $(shell llvm-config --cxxflags) -g 54 | ${FRAMEWORK_NAME}_OBJCCFLAGS += $(shell llvm-config --cxxflags) -g -fobjc-arc 55 | #LIBRARIES_DEPEND_UPON += `llvm-config --ldflags` -lLLVM-`llvm-config --version` 56 | LIBRARIES_DEPEND_UPON += $(shell llvm-config --ldflags) $(shell if [ `llvm-config --version | sed 's/\([0-9]*\).\([0-9]*\).*/\1\2/'` -gt 31 ] ; then llvm-config --libs ; else llvm-config --libs ${LLVM_LIBS} ; fi) 57 | 58 | 59 | CC = clang 60 | CXX = clang++ 61 | LD = $(CXX) 62 | 63 | ${FRAMEWORK_NAME}_RESOURCE_FILES += MsgSendSmallInt.bc 64 | 65 | ifeq ($(broken_ctype), yes) 66 | ADDITIONAL_CLANG_FLAGS+=-DBROKEN_CTYPE 67 | endif 68 | 69 | include $(GNUSTEP_MAKEFILES)/framework.make 70 | -include ../../../etoile.make 71 | -include ../../../documentation.make 72 | 73 | shared-instance-bundle-all: MsgSendSmallInt.bc 74 | 75 | MsgSendSmallInt.bc: ../Runtime/MsgSendSmallInt.m 76 | @echo "Generating LLVM bitcode for small int messages..." 77 | @clang -c $(ADDITIONAL_CLANG_FLAGS) -ftrapv -ftrapv-handler=smalltalk_overflow_handler `gnustep-config --objc-flags` -emit-llvm -fexceptions ../Runtime/MsgSendSmallInt.m -o MsgSendSmallInt.private.bc -fno-objc-arc 78 | @cp MsgSendSmallInt.private.bc MsgSendSmallInt.bc 79 | @#opt -make-runtime-lib-interface MsgSendSmallInt.private.bc -o MsgSendSmallInt.bc 80 | @rm MsgSendSmallInt.private.bc 81 | 82 | clean:: 83 | rm -f MsgSendSmallInt.bc 84 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/GenericABIInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | GenericABIInfo.h 3 | 4 | ABI information provider for platforms that don't have an explicit provider. 5 | 6 | Copyright (C) 2012 Niels Grewe 7 | 8 | Author: Niels Grewe 9 | Date: March 2012 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright notice, 17 | this list of conditions and the following disclaimer in the documentation 18 | and/or other materials provided with the distribution. 19 | * Neither the name of the Etoile project nor the names of its contributors 20 | may be used to endorse or promote products derived from this software 21 | without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 | THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | #include "ABIInfo.h" 36 | #include "LLVMCompat.h" 37 | #ifndef GenericABIInfo_h_INCLUDED 38 | #define GenericABIInfo_h_INCLUDED 39 | 40 | 41 | namespace etoile 42 | { 43 | namespace languagekit 44 | { 45 | class GenericABIInfo : public ABIInfo 46 | { 47 | private: 48 | llvm::LLVMContext &context; 49 | 50 | LLVMType *returnTypeAndRegisterUsageForRetLLVMType(LLVMType *ty, 51 | bool &onStack, 52 | unsigned &integerRegisters, 53 | unsigned &floatRegisters); 54 | public: 55 | GenericABIInfo(llvm::Module &M) : ABIInfo(M), context(md.getContext()) {} 56 | 57 | LLVMType *returnTypeForRetLLVMType(LLVMType *ty, 58 | bool &onStack); 59 | 60 | bool willPassTypeAsPointer(llvm::Type *ty); 61 | 62 | llvm::AttrListPtr attributeListForFunctionType(llvm::FunctionType *funTy, llvm::Type *retTy); 63 | }; 64 | } //namespace: languagekit 65 | } //namespace: etoile 66 | #endif //GenericABIInfo_h_INCLUDED 67 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/LLVMCodeGen.h: -------------------------------------------------------------------------------- 1 | /*** 2 | * Objective-C interface to the LLVM generator component. 3 | */ 4 | 5 | /** 6 | * Debug flag used to set whether excessive amounts of debugging info should be 7 | * spammed to stderr. 8 | */ 9 | extern int DEBUG_DUMP_MODULES; 10 | 11 | extern "C" { 12 | #import 13 | #import 14 | } 15 | 16 | namespace etoile 17 | { 18 | namespace languagekit 19 | { 20 | class CodeGenModule; 21 | } 22 | } 23 | /** 24 | * Concrete implementation of the CodeGenerator protocol using LLVM. 25 | */ 26 | @interface LLVMCodeGen : NSObject 27 | { 28 | etoile::languagekit::CodeGenModule *Builder; 29 | NSMapTable *labelledBasicBlocks; 30 | } 31 | + (NSString*) smallIntBitcodeFile; 32 | @end 33 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/ObjCXXRuntime.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is a horribly ugly hack. The old GNU runtime headers are horribly 3 | * broken with Objective-C++, but are included by GNUstep. We need to fudge 4 | * things so that we get th things that we need defined without actually 5 | * including these headers. 6 | */ 7 | #import 8 | typedef void* arglist_t; 9 | typedef void* retval_t; 10 | typedef Class MetaClass; 11 | #define __objc_api_INCLUDE_GNU 12 | #define __objc_INCLUDE_GNU 13 | #define __encoding_INCLUDE_GNU 14 | 15 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/UglyGNUHack.h: -------------------------------------------------------------------------------- 1 | #ifdef __linux__ 2 | #include 3 | @class NSString; 4 | namespace std _GLIBCXX_VISIBILITY(default) 5 | { 6 | _GLIBCXX_BEGIN_NAMESPACE_VERSION 7 | 8 | template<> 9 | inline NSString *__strong * 10 | __addressof(NSString *__strong & __r) 11 | { 12 | return &__r; 13 | } 14 | _GLIBCXX_END_NAMESPACE_VERSION 15 | } // namespace 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/UnboxPass.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/Pass.h" 2 | #include "llvm/Function.h" 3 | #include "llvm/Instructions.h" 4 | #include "llvm/GlobalAlias.h" 5 | #include "llvm/GlobalVariable.h" 6 | #include "llvm/Constants.h" 7 | #include 8 | 9 | using namespace llvm; 10 | using std::string; 11 | 12 | ///// BIG WARNING: 13 | ///// This is experimental code and not connected to the default build. 14 | ///// If you enable it and it eats your cat, expect no sympathy. 15 | 16 | 17 | namespace 18 | { 19 | class UnboxPass : public FunctionPass 20 | { 21 | 22 | public: 23 | static char ID; 24 | UnboxPass() : FunctionPass((intptr_t)&ID) {} 25 | 26 | bool getSelectorForValue(Value *b, Value **object, string &selector) 27 | { 28 | if (CallInst *v = dyn_cast(b)) 29 | { 30 | Value *calledValue = v->getCalledValue(); 31 | while (BitCastInst *val = dyn_cast(calledValue)) 32 | { 33 | calledValue = val->getOperand(0); 34 | } 35 | if (CallInst *callee = 36 | dyn_cast(calledValue)) 37 | { 38 | if (callee->getCalledFunction()->getName() 39 | == "objc_msg_lookup") 40 | { 41 | Constant *sel = (Constant*)((LoadInst*)callee->getOperand(2))->getOperand(0); 42 | if (GlobalAlias *a = dyn_cast(sel)) 43 | { 44 | sel = a->getAliasee(); 45 | } 46 | ConstantArray *sels = (ConstantArray*)((GlobalVariable*)sel->getOperand(0)->getOperand(0))->getInitializer(); 47 | ConstantInt *idx = (ConstantInt*)sel->getOperand(0)->getOperand(2); 48 | //sels->getOperand(idx->getLimitedValue())->getOperand(0)->getOperand(0)->dump(); 49 | *object = v->getOperand(1); 50 | selector = ((ConstantArray*)((GlobalVariable*)sels->getOperand(idx->getLimitedValue())->getOperand(0)->getOperand(0))->getInitializer())->getAsString(); 51 | return true; 52 | } 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | virtual bool runOnFunction(Function &F) 59 | { 60 | //llvm::cerr << "UnboxPass: " << F.getName() << "\n"; 61 | for (Function::iterator i=F.begin(), e=F.end() ; 62 | i != e ; ++i) 63 | { 64 | for (BasicBlock::iterator b=i->begin(), last=i->end() ; 65 | b != last ; ++b) 66 | { 67 | string selector; 68 | Value *obj; 69 | if (getSelectorForValue(b, &obj, selector)) 70 | { 71 | llvm::cerr << selector << "\n"; 72 | Value *original; 73 | string construtor; 74 | if (getSelectorForValue(obj, &original, construtor)) 75 | { 76 | llvm::cerr << "created with: " <dump(); 79 | } 80 | } 81 | } 82 | return false; 83 | } 84 | }; 85 | 86 | char UnboxPass::ID = 0; 87 | RegisterPass X("unbox", "Unbox Autoboxed Variabes Pass"); 88 | } 89 | 90 | FunctionPass *createUnboxPass(void) 91 | { 92 | return new UnboxPass(); 93 | } 94 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/objc_pointers.h: -------------------------------------------------------------------------------- 1 | #import 2 | #undef _ 3 | #if __cplusplus > 201100L 4 | #include 5 | using std::unordered_map; 6 | #else 7 | #include 8 | using std::tr1::unordered_map; 9 | #endif 10 | namespace { 11 | template 12 | struct object_equal 13 | { 14 | bool operator()(const X s1, const X s2) const 15 | { 16 | return (s1 == s2) || [(id)s1 isEqual: (id)s2]; 17 | } 18 | }; 19 | 20 | template 21 | struct object_hash 22 | { 23 | size_t operator()(const X s1) const 24 | { 25 | return (size_t)[(id)s1 hash]; 26 | } 27 | }; 28 | template struct object_map : public unordered_map<__strong K, V, object_hash, object_equal > {}; 29 | } 30 | -------------------------------------------------------------------------------- /LanguageKit/CodeGen/unistd.h: -------------------------------------------------------------------------------- 1 | /* See http://llvm.org/bugs/show_bug.cgi?id=4746 */ 2 | #ifdef __block 3 | # undef __block 4 | # include_next "unistd.h" 5 | # define __block __attribute__((__blocks__(byref))) 6 | #else 7 | # include_next "unistd.h" 8 | #endif 9 | -------------------------------------------------------------------------------- /LanguageKit/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # Turn off warnings as errors until LK generates no warnings 4 | ERROR_FLAG = 5 | 6 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 7 | # etoile.make doesn't detect and handle such embedded project 8 | PROJECT_DIR = $(CURDIR) 9 | 10 | # 11 | # Library 12 | # 13 | VERSION = 0.6 14 | FRAMEWORK_NAME = LanguageKit 15 | 16 | SUBPROJECTS = CodeGen Runtime 17 | 18 | ${FRAMEWORK_NAME}_OBJC_FILES = \ 19 | LKAST.m\ 20 | LKASTVisitor.m\ 21 | LKArrayExpr.m\ 22 | LKAssignExpr.m\ 23 | LKBlockExpr.m\ 24 | LKCategory.m\ 25 | LKCodeGen.m\ 26 | LKComment.m\ 27 | LKComparison.m\ 28 | LKCompiler.m\ 29 | LKCompilerErrors.m\ 30 | LKDeclRef.m\ 31 | LKEnumReference.m\ 32 | LKFunctionCall.m\ 33 | LKIfStatement.m\ 34 | LKLiteral.m\ 35 | LKLoop.m\ 36 | LKMessageSend.m\ 37 | LKMethod.m\ 38 | LKModule.m\ 39 | LKReturn.m\ 40 | LKSubclass.m\ 41 | LKSymbolRef.m\ 42 | LKSymbolTable.m\ 43 | LKToken.m\ 44 | LKTypeHelpers.m\ 45 | LKInterpreter.m\ 46 | LKInterpreterRuntime.m\ 47 | LKVariableDecl.m 48 | 49 | ${FRAMEWORK_NAME}_HEADER_FILES = \ 50 | LKAST.h\ 51 | LKASTVisitor.h\ 52 | LKArrayExpr.h\ 53 | LKAssignExpr.h\ 54 | LKBlockExpr.h\ 55 | LKCategory.h\ 56 | LKCodeGen.h\ 57 | LKComment.h\ 58 | LKComparison.h\ 59 | LKCompiler.h\ 60 | LKCompilerErrors.h\ 61 | LKDeclRef.h\ 62 | LKEnumReference.h\ 63 | LKFunctionCall.h\ 64 | LKInterpreter.h\ 65 | LKIfStatement.h\ 66 | LKLiteral.h\ 67 | LKLoop.h\ 68 | LKMessageSend.h\ 69 | LKMethod.h\ 70 | LKModule.h\ 71 | LKReturn.h\ 72 | LKSubclass.h\ 73 | LKSymbolRef.h\ 74 | LKSymbolTable.h\ 75 | LKToken.h\ 76 | LKTypeHelpers.h\ 77 | LKVariableDecl.h\ 78 | LanguageKit.h 79 | 80 | #FIXME: -fno-inline is just for debugging and will make stuff very slow. Remove it before committing. 81 | ${FRAMEWORK_NAME}_CPPFLAGS = -D_GNU_SOURCE -fno-inline 82 | ${FRAMEWORK_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value `pkg-config --cflags libffi` -fobjc-arc -fobjc-runtime=gnustep 83 | ${FRAMEWORK_NAME}_LDFLAGS += -g -lEtoileFoundation -lstdc++ -lLanguageKitRuntime 84 | ${FRAMEWORK_NAME}_CFLAGS += -Wno-implicit -g 85 | 86 | ${FRAMEWORK_NAME}_RESOURCE_FILES += ObjCConstants.plist 87 | 88 | include $(GNUSTEP_MAKEFILES)/aggregate.make 89 | -include ../../etoile.make 90 | -include ../../documentation.make 91 | include $(GNUSTEP_MAKEFILES)/framework.make 92 | -------------------------------------------------------------------------------- /LanguageKit/LKASTVisitor.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * Generic superclass for AST visitors. Visitors subclassing this implement 5 | * methods of the form: 6 | * 7 | * - (LKAST) visitComment:(LKComment*)aNode; 8 | * 9 | * Where Comment can be the suffix of any AST node subclass 10 | */ 11 | @interface LKASTVisitor : NSObject 12 | @end 13 | -------------------------------------------------------------------------------- /LanguageKit/LKASTVisitor.m: -------------------------------------------------------------------------------- 1 | #import "LanguageKit.h" 2 | #import "LKASTVisitor.h" 3 | 4 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 5 | #define DEFCLASS(x) \ 6 | @class x;\ 7 | Class x ## Class; 8 | DEFCLASS(LKArrayExpr); 9 | DEFCLASS(LKAssignExpr); 10 | DEFCLASS(LKBlockExpr); 11 | DEFCLASS(LKCategoryDef); 12 | DEFCLASS(LKComment); 13 | DEFCLASS(LKCompare); 14 | DEFCLASS(LKDeclRef); 15 | DEFCLASS(LKIfStatement); 16 | DEFCLASS(LKLiteral); 17 | DEFCLASS(LKLoop); 18 | DEFCLASS(LKMessageSend); 19 | DEFCLASS(LKMessageCascade); 20 | DEFCLASS(LKMethod); 21 | DEFCLASS(LKModule); 22 | DEFCLASS(LKReturn); 23 | DEFCLASS(LKSubclass); 24 | DEFCLASS(LKVariableDecl); 25 | 26 | @implementation LKASTVisitor 27 | #define SETCLASS(x) do {x ## Class = [x class];} while(0) 28 | + (void) initialize 29 | { 30 | if (self == [LKASTVisitor class]) 31 | { 32 | SETCLASS(LKArrayExpr); 33 | SETCLASS(LKAssignExpr); 34 | SETCLASS(LKBlockExpr); 35 | SETCLASS(LKCategoryDef); 36 | SETCLASS(LKComment); 37 | SETCLASS(LKCompare); 38 | SETCLASS(LKDeclRef); 39 | SETCLASS(LKIfStatement); 40 | SETCLASS(LKLiteral); 41 | SETCLASS(LKLoop); 42 | SETCLASS(LKMessageSend); 43 | SETCLASS(LKMessageCascade); 44 | SETCLASS(LKMethod); 45 | SETCLASS(LKModule); 46 | SETCLASS(LKReturn); 47 | SETCLASS(LKSubclass); 48 | SETCLASS(LKVariableDecl); 49 | } 50 | } 51 | 52 | #define TRYCLASS(x)\ 53 | if ([aNode isKindOfClass: LK ## x ## Class]) \ 54 | {\ 55 | SEL sel = @selector(visit ## x:);\ 56 | if ([self respondsToSelector:sel])\ 57 | {\ 58 | return [self performSelector:sel withObject:aNode];\ 59 | }\ 60 | return aNode;\ 61 | } 62 | 63 | - (LKAST*) visitASTNode:(LKAST*)aNode 64 | { 65 | TRYCLASS(ArrayExpr); 66 | TRYCLASS(AssignExpr); 67 | TRYCLASS(BlockExpr); 68 | TRYCLASS(CategoryDef); 69 | TRYCLASS(Comment); 70 | TRYCLASS(Compare); 71 | TRYCLASS(DeclRef); 72 | TRYCLASS(IfStatement); 73 | TRYCLASS(Literal); 74 | TRYCLASS(Loop); 75 | TRYCLASS(MessageSend); 76 | TRYCLASS(MessageCascade); 77 | TRYCLASS(Method); 78 | TRYCLASS(Module); 79 | TRYCLASS(Return); 80 | TRYCLASS(Subclass); 81 | TRYCLASS(VariableDecl); 82 | NSLog(@"Unrecognised AST node type: %@", [aNode class]); 83 | return aNode; 84 | } 85 | @end 86 | -------------------------------------------------------------------------------- /LanguageKit/LKArrayExpr.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKArrayExpr : LKAST { 4 | NSMutableArray *elements; 5 | } 6 | @property (strong, nonatomic) NSMutableArray *elements; 7 | + (id) arrayWithElements:(NSArray*)anArray; 8 | - (id) initWithElements:(NSArray*)anArray; 9 | @end 10 | -------------------------------------------------------------------------------- /LanguageKit/LKArrayExpr.m: -------------------------------------------------------------------------------- 1 | #import "LKArrayExpr.h" 2 | #import "LKModule.h" 3 | 4 | @implementation LKArrayExpr 5 | @synthesize elements; 6 | + (id) arrayWithElements:(NSArray*)anArray 7 | { 8 | return [[self alloc] initWithElements: anArray]; 9 | } 10 | - (id) initWithElements:(NSArray*)anArray 11 | { 12 | SUPERINIT; 13 | elements = [anArray mutableCopy]; 14 | return self; 15 | } 16 | - (BOOL)check 17 | { 18 | BOOL success = YES; 19 | FOREACH(elements, element, LKAST*) 20 | { 21 | [element setParent:self]; 22 | success &= [element check]; 23 | } 24 | return success; 25 | } 26 | - (NSString*) description 27 | { 28 | NSMutableString *str = [NSMutableString stringWithString:@"#("]; 29 | FOREACH(elements, element, LKAST*) 30 | { 31 | [str appendFormat:@"%@, ", [element description]]; 32 | } 33 | [str replaceCharactersInRange:NSMakeRange([str length] - 2, 2) withString:@")"]; 34 | return str; 35 | } 36 | - (void*) compileWithGenerator: (id)aGenerator 37 | { 38 | void *values[[elements count] + 1]; 39 | int i = 0; 40 | FOREACH(elements, element, LKAST*) 41 | { 42 | values[i++] = [element compileWithGenerator: aGenerator]; 43 | } 44 | values[i++] = [aGenerator nilConstant]; 45 | void *arrayClass = [aGenerator loadClassNamed:@"NSMutableArray"]; 46 | return [aGenerator sendMessage: @"arrayWithObjects:" 47 | types: NULL 48 | toObject: arrayClass 49 | withArgs: values 50 | count: i]; 51 | } 52 | - (void) visitWithVisitor:(id)aVisitor 53 | { 54 | [self visitArray:elements withVisitor:aVisitor]; 55 | } 56 | @end 57 | -------------------------------------------------------------------------------- /LanguageKit/LKAssignExpr.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class LKDeclRef; 4 | 5 | /** 6 | * AST node representing an assignment. 7 | */ 8 | @interface LKAssignExpr :LKAST { 9 | /** The target of the assignment. */ 10 | LKDeclRef *target; 11 | /** The expression representing the assigned value. */ 12 | LKAST *expr; 13 | } 14 | /** 15 | * Return new assignment with target and expression. 16 | */ 17 | + (id) assignWithTarget:(LKDeclRef*)aTarget expr:(LKAST*)expression; 18 | /** 19 | * Initialise new assignment with target and expression. 20 | */ 21 | - (id) initWithTarget:(LKDeclRef*)aTarget expr:(LKAST*)expression; 22 | /** 23 | * Returns the target of the assignment 24 | */ 25 | - (LKDeclRef*) target; 26 | /** 27 | * Returns the expression representing the assigned value. 28 | */ 29 | - (LKAST*) expression; 30 | @end 31 | -------------------------------------------------------------------------------- /LanguageKit/LKAssignExpr.m: -------------------------------------------------------------------------------- 1 | #import "LKAssignExpr.h" 2 | #import "LKDeclRef.h" 3 | #import "LKCompilerErrors.h" 4 | 5 | @implementation LKAssignExpr 6 | + (void) initialize 7 | { 8 | if (self != [LKAssignExpr class]) { return; } 9 | } 10 | + (id) assignWithTarget:(LKDeclRef*)aTarget expr:(LKAST*)expression 11 | { 12 | return [[self alloc] initWithTarget:aTarget expr:expression]; 13 | } 14 | - (id) initWithTarget:(LKDeclRef*)aTarget expr:(LKAST*)expression 15 | { 16 | SUPERINIT; 17 | ASSIGN(target, aTarget); 18 | ASSIGN(expr, expression); 19 | return self; 20 | } 21 | - (BOOL)check 22 | { 23 | [expr setParent:self]; 24 | [target setParent:self]; 25 | BOOL check = [target check] && [expr check]; 26 | if ( [target isKindOfClass: [LKBuiltinSymbol class]] ) 27 | { 28 | NSDictionary *errorDetails = D( 29 | [NSString stringWithFormat: @"Trying to assign to a builtin symbol: %@", 30 | target], kLKHumanReadableDescription, 31 | self, kLKASTNode); 32 | if ([LKCompiler reportError: LKInvalidSelectorError 33 | details: errorDetails]) 34 | { 35 | return [self check]; 36 | } 37 | return NO; 38 | } 39 | /* 40 | if (check && [[target->symbol typeEncoding] characterAtIndex: 0] != '@') 41 | { 42 | [NSException raise: @"InvalidAssignmentException" 43 | format: @"Can not yet generate code for assignment"]; 44 | } 45 | */ 46 | return check; 47 | } 48 | - (NSString*) description 49 | { 50 | return [NSString stringWithFormat:@"%@ := %@", [target symbol], expr]; 51 | } 52 | - (void*) compileWithGenerator: (id)aGenerator 53 | { 54 | void * rval = [expr compileWithGenerator: aGenerator]; 55 | LKSymbol *symbol = [target symbol]; 56 | switch([symbol scope]) 57 | { 58 | case LKSymbolScopeLocal: 59 | case LKSymbolScopeExternal: 60 | case LKSymbolScopeArgument: 61 | case LKSymbolScopeObject: 62 | case LKSymbolScopeClass: 63 | [aGenerator storeValue: rval inVariable: symbol]; 64 | break; 65 | case LKSymbolScopeGlobal: 66 | default: 67 | return [super compileWithGenerator: aGenerator]; 68 | } 69 | // Assignments aren't expressions in Smalltalk, but they might be in some 70 | // other language that wants to use this code and it doesn't cost more than 71 | // returning NULL. 72 | return rval; 73 | } 74 | - (void) visitWithVisitor:(id)aVisitor 75 | { 76 | id tmp = [aVisitor visitASTNode:target]; 77 | ASSIGN(target, tmp); 78 | [target visitWithVisitor:aVisitor]; 79 | 80 | tmp = [aVisitor visitASTNode:expr]; 81 | ASSIGN(expr, tmp); 82 | [expr visitWithVisitor:aVisitor]; 83 | } 84 | - (LKDeclRef*) target 85 | { 86 | return target; 87 | } 88 | - (LKAST*) expression 89 | { 90 | return expr; 91 | } 92 | @end 93 | -------------------------------------------------------------------------------- /LanguageKit/LKAutoBoxFixup.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | struct objc_slot* objc_get_slot(Class cls, SEL selector); 7 | 8 | static struct objc_slot* objc_method_type_fixup(Class cls, SEL 9 | selector, struct objc_slot *result) 10 | { 11 | LOCAL_AUTORELEASE_POOL(); 12 | id jit = defaultJIT(); 13 | const char *selName = sel_getName(selector); 14 | const char *selTypes = sel_getType_np(selector); 15 | [jit startModule: nil]; 16 | [jit createCategoryWithName: @"Type_Fixup" 17 | onClassNamed: [NSString stringWithUTF8String: class_getName(cls)]]; 18 | if (class_isMetaClass(cls)) 19 | { 20 | [jit beginClassMethod: selName 21 | withTypes: selTypes 22 | locals: NULL 23 | count: 0]; 24 | } 25 | else 26 | { 27 | [jit beginInstanceMethod: selName 28 | withTypes: selTypes 29 | locals: NULL 30 | count: 0]; 31 | } 32 | SEL correctSel = sel_registerTypedName_np(selName, result->types); 33 | Method m = class_getInstanceMethod(cls, correctSel); 34 | int argc = method_getNumberOfArguments(m) - 2; 35 | void *argv[argc]; 36 | for (int i=0 ; itypes 42 | toObject: [jit loadSelf] 43 | withArgs: argv 44 | count: argc]; 45 | if (selTypes[0] != 'v' && result->types[0] != 'v') 46 | { 47 | [jit setReturn: ret]; 48 | } 49 | [jit endMethod]; 50 | [jit endCategory]; 51 | [jit endModule]; 52 | return objc_get_slot(cls, selector); 53 | } 54 | -------------------------------------------------------------------------------- /LanguageKit/LKBlockExpr.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a block closure expression. 5 | */ 6 | @interface LKBlockExpr : LKAST { 7 | /** List of statements in this node. */ 8 | NSMutableArray * statements; 9 | } 10 | /** 11 | * Return a new Block with the specified arguments, locals and statements. 12 | */ 13 | + (id) blockWithArguments:(NSMutableArray*)arguments locals:(NSMutableArray*)locals statements:(NSMutableArray*)statementList; 14 | /** 15 | * Initialise a new Block with the specified arguments, locals and statements. 16 | */ 17 | - (id) initWithArguments:(NSMutableArray*)arguments locals:(NSMutableArray*)locals statements:(NSMutableArray*)statementList; 18 | /** 19 | * Set the statements in this node. 20 | */ 21 | - (void) setStatements: (NSMutableArray*)statements; 22 | /** 23 | * Returns the list of statements in the block 24 | */ 25 | - (NSMutableArray*) statements; 26 | @end 27 | -------------------------------------------------------------------------------- /LanguageKit/LKCategory.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a new category definition. 5 | */ 6 | @interface LKCategoryDef : LKAST { 7 | /** Name of this class. */ 8 | NSString * classname; 9 | /** Name of the category. */ 10 | NSString *categoryName; 11 | /** Array of methods defined in this category. */ 12 | NSMutableArray *methods; 13 | } 14 | 15 | @property (readonly, nonatomic) NSString *classname; 16 | @property (readonly, nonatomic) NSString *categoryName; 17 | @property (readonly, nonatomic) NSMutableArray *methods; 18 | 19 | /** 20 | * Return a new Category with the specified name, class and list of 21 | * methods. The third argument is an array of AST nodes representing methods. 22 | */ 23 | + (id) categoryWithName:(NSString*)aName 24 | onClassNamed:(NSString*)aClass 25 | methods:(NSArray*)aMethodList; 26 | /** 27 | * Returns a new anonymous category. 28 | */ 29 | + (id) categoryOnClassNamed:(NSString*)aName methods:(NSArray*)aMethodList; 30 | 31 | /** 32 | * Returns the methods. 33 | */ 34 | - (NSMutableArray*) methods; 35 | @end 36 | -------------------------------------------------------------------------------- /LanguageKit/LKCategory.m: -------------------------------------------------------------------------------- 1 | #import "LKCategory.h" 2 | 3 | @implementation LKCategoryDef 4 | 5 | @synthesize classname, categoryName, methods; 6 | 7 | - (id) initWithName:(NSString*)aName 8 | class:(NSString*)aClass 9 | methods:(NSArray*)aMethodList 10 | { 11 | SUPERINIT; 12 | ASSIGN(classname, aClass); 13 | ASSIGN(categoryName, aName); 14 | ASSIGN(methods, [aMethodList mutableCopy]); 15 | return self; 16 | } 17 | + (id) categoryWithName:(NSString*)aName 18 | onClassNamed:(NSString*)aClass 19 | methods:(NSArray*)aMethodList 20 | { 21 | return [[self alloc] initWithName:aName 22 | class:aClass 23 | methods:aMethodList]; 24 | } 25 | + (id) categoryOnClassNamed:(NSString*)aName methods:(NSArray*)aMethodList 26 | { 27 | return [self categoryWithName:@"AnonymousCategory" 28 | onClassNamed:aName 29 | methods:aMethodList]; 30 | } 31 | - (BOOL)check 32 | { 33 | symbols = [LKSymbolTable symbolTableForClass: classname]; 34 | BOOL success = YES; 35 | FOREACH(methods, method, LKAST*) 36 | { 37 | [method setParent:self]; 38 | success &= [method check]; 39 | } 40 | return success; 41 | } 42 | - (NSString*) description 43 | { 44 | NSMutableString *str = [NSMutableString stringWithFormat:@"%@ extend [ \n", 45 | classname]; 46 | FOREACH(methods, method, LKAST*) 47 | { 48 | [str appendString:[method description]]; 49 | } 50 | [str appendString:@"\n]"]; 51 | return str; 52 | } 53 | 54 | - (void*) compileWithGenerator: (id)aGenerator 55 | { 56 | [aGenerator createCategoryWithName:categoryName 57 | onClassNamed:classname]; 58 | FOREACH(methods, method, LKAST*) 59 | { 60 | [method compileWithGenerator: aGenerator]; 61 | } 62 | [aGenerator endCategory]; 63 | if ([[LKAST code] objectForKey: classname] == nil) 64 | { 65 | [[LKAST code] setObject: [NSMutableArray array] forKey: classname]; 66 | } 67 | [[[LKAST code] objectForKey: classname] addObject: self]; 68 | return NULL; 69 | } 70 | 71 | - (void) visitWithVisitor:(id)aVisitor 72 | { 73 | [self visitArray:methods withVisitor:aVisitor]; 74 | } 75 | @end 76 | -------------------------------------------------------------------------------- /LanguageKit/LKCodeGen.m: -------------------------------------------------------------------------------- 1 | #import "LKCompiler.h" 2 | #import "LKCodeGen.h" 3 | 4 | static Class defaultJitClass; 5 | static Class defaultStaticClass; 6 | 7 | 8 | @implementation LKCodeGenLoader 9 | + (void) initialize 10 | { 11 | if (self == [LKCodeGenLoader class]) 12 | { 13 | [LKCompiler loadFrameworkNamed: @"LanguageKitCodeGen"]; 14 | defaultJitClass = NSClassFromString(@"LLVMCodeGen"); 15 | defaultStaticClass = NSClassFromString(@"LLVMStaticCodeGen"); 16 | } 17 | } 18 | + (id) defaultJIT 19 | { 20 | return [defaultJitClass new]; 21 | } 22 | + (id) defaultStaticCompilerWithFile:(NSString*)outFile 23 | { 24 | return [[defaultStaticClass alloc] initWithFile:outFile]; 25 | } 26 | @end 27 | id defaultJIT(void) 28 | { 29 | return [LKCodeGenLoader defaultJIT]; 30 | } 31 | id defaultStaticCompilterWithFile(NSString* outFile) 32 | { 33 | return [LKCodeGenLoader defaultStaticCompilerWithFile:outFile]; 34 | } 35 | -------------------------------------------------------------------------------- /LanguageKit/LKComment.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKComment : LKAST { 4 | NSString *comment; 5 | } 6 | /** 7 | * Creates a new comment with the given string. 8 | */ 9 | + (LKComment*) commentWithString:(NSString*)aString; 10 | /** 11 | * Returns the string value of the comment. 12 | */ 13 | - (NSString*) stringValue; 14 | @end 15 | -------------------------------------------------------------------------------- /LanguageKit/LKComment.m: -------------------------------------------------------------------------------- 1 | #import "LKComment.h" 2 | 3 | @implementation LKComment 4 | - (LKComment*) initWithString:(NSString*)aString 5 | { 6 | SUPERINIT; 7 | ASSIGN(comment, aString); 8 | return self; 9 | } 10 | + (LKComment*) commentWithString:(NSString*)aString 11 | { 12 | return [[LKComment alloc] initWithString:aString]; 13 | } 14 | - (NSString*) description 15 | { 16 | return [NSString stringWithFormat:@"\"%@\"", comment]; 17 | } 18 | - (NSString*) stringValue 19 | { 20 | return comment; 21 | } 22 | - (void*) compileWithGenerator: (id)aGenerator 23 | { 24 | // Comments do not turn into code. 25 | return NULL; 26 | } 27 | - (BOOL) isComment 28 | { 29 | return YES; 30 | } 31 | // Comments are always semantically valid - no checking needed. 32 | - (BOOL) check { return YES; } 33 | @end 34 | -------------------------------------------------------------------------------- /LanguageKit/LKComparison.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKCompare : LKAST { 4 | LKAST *lhs; 5 | LKAST *rhs; 6 | } 7 | + (LKCompare*) comparisonWithLeftExpression: (LKAST*)expr1 8 | rightExpression: (LKAST*)expr2; 9 | @end 10 | -------------------------------------------------------------------------------- /LanguageKit/LKComparison.m: -------------------------------------------------------------------------------- 1 | #import "LKComparison.h" 2 | 3 | @implementation LKCompare 4 | - (LKCompare*) initWithLeftExpression: (LKAST*)expr1 5 | rightExpression: (LKAST*)expr2; 6 | { 7 | SUPERINIT; 8 | ASSIGN(lhs, expr1); 9 | ASSIGN(rhs, expr2); 10 | return self; 11 | } 12 | + (LKCompare*) comparisonWithLeftExpression: (LKAST*)expr1 13 | rightExpression: (LKAST*)expr2; 14 | { 15 | return [[LKCompare alloc] initWithLeftExpression:expr1 16 | rightExpression: expr2]; 17 | } 18 | - (NSString*) description 19 | { 20 | return [NSString stringWithFormat:@"%@ = %@", lhs, rhs]; 21 | } 22 | - (BOOL)check 23 | { 24 | [lhs setParent:self]; 25 | [rhs setParent:self]; 26 | return [lhs check] && [rhs check]; 27 | } 28 | - (void*) compileWithGenerator: (id)aGenerator 29 | { 30 | void * l = [lhs compileWithGenerator: aGenerator]; 31 | void * r = [rhs compileWithGenerator: aGenerator]; 32 | return [aGenerator comparePointer:l to:r]; 33 | } 34 | - (void) visitWithVisitor:(id)aVisitor 35 | { 36 | id tmp = [aVisitor visitASTNode:lhs]; 37 | ASSIGN(lhs, tmp); 38 | [rhs visitWithVisitor:aVisitor]; 39 | 40 | tmp = [aVisitor visitASTNode:rhs]; 41 | ASSIGN(rhs, tmp); 42 | [rhs visitWithVisitor:aVisitor]; 43 | } 44 | @end 45 | -------------------------------------------------------------------------------- /LanguageKit/LKCompilerErrors.h: -------------------------------------------------------------------------------- 1 | #import 2 | /** 3 | * If this file is being included as normal, then declare extern versions of 4 | * the string. If it is being included in the file used for generating the 5 | * real versions of the strings then create the unique string instances. 6 | */ 7 | #ifndef EMIT_STRING 8 | #define EMIT_STRING(x) extern NSString *x; 9 | #endif 10 | /** 11 | * Key used for the human readable error or warning description. 12 | */ 13 | EMIT_STRING(kLKHumanReadableDescription) 14 | /** 15 | * Key used to indicate the AST node responsible for the warning. 16 | */ 17 | EMIT_STRING(kLKASTNode) 18 | /** 19 | * The name of the missing superclass. Used for LKUndefinedSuperclass. 20 | */ 21 | EMIT_STRING(kLKMissingSuperclassName) 22 | /** 23 | * Line number of a parser error. 24 | */ 25 | EMIT_STRING(kLKLineNumber) 26 | /** 27 | * Text of the line containing an error. 28 | */ 29 | EMIT_STRING(kLKSourceLine) 30 | /** 31 | * The character which generated the error. 32 | */ 33 | EMIT_STRING(kLKCharacterNumber) 34 | /** 35 | * The type encoding associated with an error or warning. 36 | */ 37 | EMIT_STRING(kLKTypeEncoding) 38 | /** 39 | * The name of a header that can't be loaded. 40 | */ 41 | EMIT_STRING(kLKHeaderName) 42 | 43 | /** 44 | * A reference was made to an invalid symbol. 45 | */ 46 | EMIT_STRING(LKUndefinedSymbolError) 47 | /** 48 | * The selector may not be used in LanguageKit code. 49 | */ 50 | EMIT_STRING(LKInvalidSelectorError) 51 | /** 52 | * The compiler can't determine the type encoding for a referenced symbol. 53 | */ 54 | EMIT_STRING(LKUnknownTypeError) 55 | /** 56 | * An attempt was made to subclass a nonexistent class. This error is usually 57 | * fatal, but can be recovered by adding the superclass to the runtime. The 58 | * name of the missing superclass will be stored in the dictionary with the 59 | * kLKMissingSuperclassName key. 60 | */ 61 | EMIT_STRING(LKUndefinedSuperclassError) 62 | /** 63 | * An attempt was made to compile a class which already exists. This is only a 64 | * problem when JIT compiling; emitting a copy of a currently-loaded class is 65 | * perfectly acceptable. 66 | */ 67 | EMIT_STRING(LKRedefinedClassWarning) 68 | /** 69 | * A selector is being used that is polymorphic. The kLKTypeEncoding key will 70 | * provide the type encoding that was chosen. 71 | */ 72 | EMIT_STRING(LKPolymorphicSelectorWarning) 73 | /** 74 | * A C header was referenced, but can't be loaded. kLKHeaderName will provide 75 | * the name of the header. 76 | */ 77 | EMIT_STRING(LKMissingHeaderWarning) 78 | /** 79 | * Parsing failed. The info dictionary will contain kLKCharacterNumber, 80 | * kLKSourceLine, and kLKLineNumber to identify the location of the error. 81 | */ 82 | EMIT_STRING(LKParserError) 83 | /** 84 | * A specified enumerated type does not exist. 85 | */ 86 | EMIT_STRING(LKEnumError) 87 | #undef EMIT_STRING 88 | -------------------------------------------------------------------------------- /LanguageKit/LKCompilerErrors.m: -------------------------------------------------------------------------------- 1 | #define EMIT_STRING(x) NSString *x = @"" # x; 2 | #include 3 | -------------------------------------------------------------------------------- /LanguageKit/LKDeclRef.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a reference to a variable. 5 | */ 6 | @interface LKDeclRef : LKAST 7 | /** The name of the variable being referenced. This is initially set to a 8 | * string and later resolved to a symbol. */ 9 | @property (strong, nonatomic) id symbol; 10 | /** Returns autoreleased reference for the specified symbol. */ 11 | + (id) referenceWithSymbol:(NSString*)sym; 12 | @end 13 | 14 | /** 15 | * Abstract class for all built-in symbols. These are subclasses of LKDeclRef, 16 | * so it's possible to set their name. For example, a Java-like language may 17 | * choose to call the self builtin 'this', or a Go-like frontend may give it a 18 | * different name for every method. 19 | */ 20 | @interface LKBuiltinSymbol : LKDeclRef 21 | /** 22 | * Returns a new autoreleased instance of he receiver. 23 | */ 24 | + (LKBuiltinSymbol*)builtin; 25 | @end 26 | 27 | /** 28 | * A nil (object) value. 29 | */ 30 | @interface LKNilRef : LKBuiltinSymbol @end 31 | /** 32 | * Reference to the receiver, in methods and blocks inside methods. 33 | */ 34 | @interface LKSelfRef : LKBuiltinSymbol @end 35 | /** 36 | * Reference to the superclass of he receiver. 37 | */ 38 | @interface LKSuperRef : LKBuiltinSymbol @end 39 | /** 40 | * Reference to the block object, from within its scope. 41 | */ 42 | @interface LKBlockSelfRef : LKBuiltinSymbol @end 43 | -------------------------------------------------------------------------------- /LanguageKit/LKDeclRef.m: -------------------------------------------------------------------------------- 1 | #import "LKDeclRef.h" 2 | #import "LKSymbolTable.h" 3 | #import "LKCompiler.h" 4 | #import "LKCompilerErrors.h" 5 | 6 | 7 | @implementation LKDeclRef 8 | @synthesize symbol; 9 | - (id) initWithSymbol:(NSString*)sym 10 | { 11 | SUPERINIT; 12 | ASSIGN(symbol, sym); 13 | return self; 14 | } 15 | + (id) referenceWithSymbol:(NSString*)sym 16 | { 17 | return [[self alloc] initWithSymbol: sym]; 18 | } 19 | - (BOOL)check 20 | { 21 | // If we've already done this check, reset the symbol and do it again 22 | if (![symbol isKindOfClass: [NSString class]]) 23 | { 24 | ASSIGN(symbol, [symbol name]); 25 | } 26 | if ([symbol characterAtIndex: 0] == '#') { return YES; } 27 | 28 | LKSymbol *s = [symbols symbolForName: symbol]; 29 | if (nil == s) 30 | { 31 | NSDictionary *errorDetails = D( 32 | [NSString stringWithFormat: @"Unrecognised symbol: %@", 33 | symbol], kLKHumanReadableDescription, 34 | self, kLKASTNode); 35 | if ([LKCompiler reportError: LKUndefinedSymbolError 36 | details: errorDetails]) 37 | { 38 | return [self check]; 39 | } 40 | return NO; 41 | } 42 | else 43 | { 44 | ASSIGN(symbol, s); 45 | } 46 | return YES; 47 | } 48 | - (NSString*) description 49 | { 50 | return [symbol description]; 51 | } 52 | - (void*) compileWithGenerator: (id)aGenerator 53 | { 54 | NSString *symbolName = [symbol name]; 55 | switch([symbol scope]) 56 | { 57 | case LKSymbolScopeLocal: 58 | case LKSymbolScopeExternal: 59 | case LKSymbolScopeArgument: 60 | case LKSymbolScopeObject: 61 | case LKSymbolScopeClass: 62 | return [aGenerator loadVariable: symbol]; 63 | case LKSymbolScopeGlobal: 64 | return [aGenerator loadClassNamed: symbolName]; 65 | default: 66 | NSLog(@"Compiling declref to symbol %@ of type %d", 67 | symbol, [symbol scope]); 68 | return [super compileWithGenerator: aGenerator]; 69 | } 70 | } 71 | - (NSString*) symbol 72 | { 73 | return symbol; 74 | } 75 | @end 76 | 77 | @implementation LKBuiltinSymbol 78 | + (LKBuiltinSymbol*)builtin 79 | { 80 | return [[self alloc] init]; 81 | } 82 | - (BOOL)check { return YES; } 83 | @end 84 | 85 | @implementation LKNilRef 86 | - (void*) compileWithGenerator: (id)aGenerator 87 | { 88 | return [aGenerator nilConstant]; 89 | } 90 | @end 91 | @implementation LKSelfRef 92 | - (void*) compileWithGenerator: (id)aGenerator 93 | { 94 | return [aGenerator loadSelf]; 95 | } 96 | @end 97 | @implementation LKSuperRef 98 | - (void*) compileWithGenerator: (id)aGenerator 99 | { 100 | return [aGenerator loadSelf]; 101 | } 102 | // TODO: Reject super as anything other than the target of a message expression 103 | @end 104 | @implementation LKBlockSelfRef 105 | // TODO: Reject blockContext when not in a block scope 106 | - (void*) compileWithGenerator: (id)aGenerator 107 | { 108 | return [aGenerator loadBlockContext]; 109 | } 110 | @end 111 | -------------------------------------------------------------------------------- /LanguageKit/LKEnumReference.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKEnumReference : LKAST 4 | { 5 | NSString *enumName; 6 | NSString *enumValue; 7 | long long value; 8 | } 9 | - (id)initWithValue: (NSString*)aValue inEnumeration: (NSString*)anEnum; 10 | @end 11 | -------------------------------------------------------------------------------- /LanguageKit/LKEnumReference.m: -------------------------------------------------------------------------------- 1 | #import "LKEnumReference.h" 2 | #import "LKCompiler.h" 3 | #import "LKCompilerErrors.h" 4 | #import "SourceCodeKit/SCKIntrospection.h" 5 | 6 | @interface LKCompiler (PrivateStuff) 7 | + (id)valueOf: (NSString*)enumName inEnumeration: (NSString*)anEnumeration; 8 | @end 9 | 10 | 11 | @implementation LKEnumReference 12 | - (id)initWithValue: (NSString*)aValue inEnumeration: (NSString*)anEnum 13 | { 14 | enumName = anEnum; 15 | enumValue = aValue; 16 | return self; 17 | } 18 | 19 | - (BOOL)check 20 | { 21 | id val = [LKCompiler valueOf: enumValue inEnumeration: enumName]; 22 | if (val == nil || [val isKindOfClass: [NSArray class]]) 23 | { 24 | NSDictionary *errorDetails = D( 25 | [NSString stringWithFormat: @"Value %@ not found in enumeration %@", enumValue, enumName], 26 | kLKHumanReadableDescription, 27 | self, kLKASTNode); 28 | if ([LKCompiler reportError: LKEnumError 29 | details: errorDetails]) 30 | { 31 | return [self check]; 32 | } 33 | return NO; 34 | } 35 | SCKEnumerationValue *ev = val; 36 | value = [ev longLongValue]; 37 | return YES; 38 | } 39 | - (void*) compileWithGenerator: (id)aGenerator 40 | { 41 | return [aGenerator intConstant: [NSString stringWithFormat: @"%lld", value]]; 42 | } 43 | @end 44 | -------------------------------------------------------------------------------- /LanguageKit/LKFunction.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | /** 5 | * AST node representing a function. 6 | */ 7 | @interface LKFunction : LKAST 8 | /** Function signature - selector, type encoding, and names of arguments. */ 9 | @property (retain, nonatomic) LKFunctionCall *signature; 10 | /** List of statements in this function. */ 11 | @property (retain, nonatomic) NSMutableArray *statements; 12 | /** 13 | * Return a new Function with the specified signature, locals and statements. 14 | */ 15 | + (id) functionWithSignature: (LKFunctionCall*)aSignature 16 | locals: (NSMutableArray*)locals 17 | statements: (NSMutableArray*)statementList; 18 | /** 19 | * Initialise a new Function with the specified signature, locals and statements. 20 | */ 21 | - (id) initWithSignature: (LKFunctionCall*)aSignature 22 | locals: (NSMutableArray*)localss 23 | statements: (NSMutableArray*)statementList; 24 | /** 25 | * Set the function signature for this function. 26 | */ 27 | - (void) setSignature:(LKFunctionCall*)aSignature; 28 | /** 29 | * Returns the function's body 30 | */ 31 | - (NSString*) functionBody; 32 | @end 33 | 34 | -------------------------------------------------------------------------------- /LanguageKit/LKFunction.m: -------------------------------------------------------------------------------- 1 | #import "LKFunction.h" 2 | #import "LKModule.h" 3 | #import "LKCompilerErrors.h" 4 | 5 | 6 | @implementation LKFunction 7 | @synthesize signature, statements; 8 | + (id) functionWithSignature:(LKFunctionCall*)aSignature 9 | locals:(NSMutableArray*)locals 10 | statements:(NSMutableArray*)statementList 11 | { 12 | return [[[self alloc] initWithSignature: aSignature 13 | locals: locals 14 | statements: statementList] autorelease]; 15 | } 16 | - (id) initWithSignature:(LKFunctionCall*)aSignature 17 | locals:(NSMutableArray*)locals 18 | statements:(NSMutableArray*)statementList 19 | { 20 | LKSymbolTable *st = [LKSymbolTable new]; 21 | [st setDeclarationScope: self]; 22 | [st addSymbolsNamed: locals ofKind: LKSymbolScopeLocal]; 23 | [st addSymbolsNamed: [aSignature arguments] ofKind: LKSymbolScopeArgument]; 24 | self = [self initWithSymbolTable: st]; 25 | [st release]; 26 | if (self == nil) { return nil; } 27 | ASSIGN(signature, aSignature); 28 | ASSIGN(statements, statementList); 29 | return self; 30 | } 31 | - (void)dealloc 32 | { 33 | [signature release]; 34 | [statements release]; 35 | [super dealloc]; 36 | } 37 | - (BOOL)check 38 | { 39 | NSInteger i = 0; 40 | // Make sure that the arguments are all in the right order in the symbol table. 41 | for (NSString *arg in [signature arguments]) 42 | { 43 | LKSymbol *argSymbol = [symbols symbolForName: arg]; 44 | [argSymbol setIndex: i++]; 45 | } 46 | 47 | BOOL success = YES; 48 | FOREACH(statements, statement, LKAST*) 49 | { 50 | [statement setParent:self]; 51 | success &= [statement check]; 52 | } 53 | return success; 54 | } 55 | - (NSString*) functionBody 56 | { 57 | NSMutableString *str = [NSMutableString string]; 58 | if ([[symbols locals] count]) 59 | { 60 | [str appendString:@"| "]; 61 | for (NSString *symbol in [symbols locals]) 62 | { 63 | [str appendFormat:@"%@ ", symbol]; 64 | } 65 | [str appendString:@"|\n"]; 66 | } 67 | for (LKAST *statement in statements) 68 | { 69 | [str appendFormat:@"%@.\n", statement]; 70 | } 71 | return str; 72 | } 73 | - (NSString*) description 74 | { 75 | NSMutableString *str = [NSMutableString string]; 76 | 77 | [str appendString:[signature description]]; 78 | [str appendString:@"[\n"]; 79 | [str appendString: [self functionBody]]; 80 | [str appendString:@"]"]; 81 | return str; 82 | } 83 | - (void*) compileWithGenerator: (id)aGenerator 84 | { 85 | [aGenerator beginFunction: [signature functionName] 86 | withTypeEncoding: [signature typeEncoding]; 87 | arguments: [symbols arguments] 88 | locals: [symbols locals]]; 89 | for (LKAST *statement in statements) 90 | { 91 | [statement compileWithGenerator: aGenerator]; 92 | } 93 | [aGenerator endFunction]; 94 | return NULL; 95 | } 96 | - (void) inheritSymbolTable:(LKSymbolTable*)aSymbolTable 97 | { 98 | [symbols setEnclosingScope: aSymbolTable]; 99 | } 100 | - (void) visitWithVisitor:(id)aVisitor 101 | { 102 | [self visitArray: statements withVisitor: aVisitor]; 103 | } 104 | @end 105 | 106 | -------------------------------------------------------------------------------- /LanguageKit/LKFunctionCall.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a call to a C function. 5 | */ 6 | @interface LKFunctionCall : LKAST 7 | /** 8 | * The name of the called function. 9 | */ 10 | @property (nonatomic, strong) NSString *functionName; 11 | /** 12 | * The type encoding of the function. 13 | */ 14 | @property (nonatomic, strong) NSString *typeEncoding; 15 | /** 16 | * The function arguments. 17 | */ 18 | @property (nonatomic, strong) NSMutableArray *arguments; 19 | @end 20 | 21 | -------------------------------------------------------------------------------- /LanguageKit/LKFunctionCall.m: -------------------------------------------------------------------------------- 1 | #import "LKFunctionCall.h" 2 | #import "LKCompiler.h" 3 | #import "LKCompilerErrors.h" 4 | 5 | @interface LKCompiler (PrivateStuff) 6 | + (NSString*)typesForFunction: (NSString*)functionName; 7 | @end 8 | 9 | @implementation LKFunctionCall 10 | @synthesize functionName, typeEncoding, arguments; 11 | - (BOOL)check 12 | { 13 | ASSIGN(typeEncoding, [LKCompiler typesForFunction: functionName]); 14 | if (nil == typeEncoding) 15 | { 16 | NSDictionary *errorDetails = D( 17 | [NSString stringWithFormat: @"Can not determine type for %@", functionName], 18 | kLKHumanReadableDescription, 19 | self, kLKASTNode); 20 | if ([LKCompiler reportError: LKUnknownTypeError 21 | details: errorDetails]) 22 | { 23 | return [self check]; 24 | } 25 | return NO; 26 | } 27 | for (LKAST *node in arguments) 28 | { 29 | [node setParent: self]; 30 | if (![node check]) 31 | { 32 | return NO; 33 | } 34 | } 35 | return YES; 36 | } 37 | - (void*) compileWithGenerator: (id)aGenerator 38 | { 39 | int count = [arguments count]; 40 | void *args[count]; 41 | int i = 0; 42 | for (LKAST *arg in arguments) 43 | { 44 | args[i++] = [arg compileWithGenerator: aGenerator]; 45 | } 46 | return [aGenerator callFunction: functionName 47 | typeEncoding: typeEncoding 48 | arguments: args 49 | count: count]; 50 | } 51 | - (NSString*)description 52 | { 53 | NSMutableString *str = [functionName mutableCopy]; 54 | [str appendString: @"("]; 55 | for (LKAST *arg in arguments) 56 | { 57 | [str appendString: [arg description]]; 58 | [str appendString: @", "]; 59 | } 60 | [str appendString: @")"]; 61 | return str; 62 | } 63 | @end 64 | 65 | -------------------------------------------------------------------------------- /LanguageKit/LKIfStatement.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKIfStatement : LKAST { 4 | LKAST *condition; 5 | NSMutableArray *thenStatements; 6 | NSMutableArray *elseStatements; 7 | } 8 | + (LKIfStatement*) ifStatementWithCondition:(LKAST*) aCondition 9 | then:(NSArray*)thenClause 10 | else:(NSArray*)elseClause; 11 | + (LKIfStatement*) ifStatementWithCondition:(LKAST*) aCondition; 12 | - (void)setElseStatements:(NSArray*)elseClause; 13 | - (void)setThenStatements:(NSArray*)thenClause; 14 | @end 15 | -------------------------------------------------------------------------------- /LanguageKit/LKInterpreter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | 7 | extern NSString *LKInterpreterException; 8 | 9 | LKMethod *LKASTForMethod(Class cls, NSString *selectorName); 10 | 11 | 12 | /** 13 | * Structure for looking up the scope of a variable in interpreter contexts. 14 | */ 15 | typedef struct 16 | { 17 | /** 18 | * The scope of this symbol, once external references have been resolved. 19 | */ 20 | LKSymbolScope scope; 21 | /** 22 | * The context where this variable can be accessed. 23 | */ 24 | __unsafe_unretained LKInterpreterContext *context; 25 | } LKInterpreterVariableContext; 26 | 27 | /** 28 | * Wrapper around a map table which contains the objects in a 29 | * Smalltalk stack frame. 30 | */ 31 | @interface LKInterpreterContext : NSObject 32 | { 33 | @public 34 | LKInterpreterContext *parent; 35 | LKSymbolTable *symbolTable; 36 | @private 37 | NSMutableDictionary *objects; 38 | } 39 | @property (unsafe_unretained, nonatomic) id selfObject; 40 | @property (strong, nonatomic) id blockContextObject; 41 | - (id) initWithSymbolTable: (LKSymbolTable*)aTable 42 | parent: (LKInterpreterContext*)aParent; 43 | - (void) setValue: (id)value forSymbol: (NSString*)symbol; 44 | - (id) valueForSymbol: (NSString*)symbol; 45 | - (LKInterpreterVariableContext)contextForSymbol: (LKSymbol*)symbol; 46 | @end 47 | 48 | 49 | @interface LKAST (LKInterpreter) 50 | - (id)interpretInContext: (LKInterpreterContext*)context; 51 | @end 52 | 53 | @interface LKBlockExpr (LKInterpreter) 54 | - (id)interpretInContext: (LKInterpreterContext*)context; 55 | - (id)executeBlock: (id)block 56 | WithArguments: (const id*)args 57 | count: (int)count 58 | inContext: (LKInterpreterContext*)context; 59 | @end 60 | 61 | @interface LKMethod (LKInterpreter) 62 | - (id)executeInContext: (LKInterpreterContext*)context; 63 | - (id)executeWithReciever: (id)receiver arguments: (const id*)args count: (int)count; 64 | @end 65 | 66 | @interface LKSubclass (LKInterpreter) 67 | - (void)setValue: (id)value forClassVariable: (NSString*)cvar; 68 | - (id)valueForClassVariable: (NSString*)cvar; 69 | @end 70 | -------------------------------------------------------------------------------- /LanguageKit/LKInterpreterRuntime.h: -------------------------------------------------------------------------------- 1 | #import 2 | /** 3 | * These functions allow the interpreter to interact with the Objective-C 4 | * runtime. 5 | */ 6 | 7 | /** 8 | * Send a message to an object. receiverClass is the class to start looking 9 | * for the method implementation in; normally receiver's class, but if it is 10 | * a super message send it should be the appropriate superclass of receiver. 11 | * 12 | * Arguments are unboxed to the correct type, and the returned value 13 | * is boxed to an object. 14 | * 15 | * Throws an exception if any of the arguments can't be unboxed to the 16 | * required type for the message send. 17 | */ 18 | id LKSendMessage(NSString *className, id receiver, NSString *selName, 19 | unsigned int argc, const id *args); 20 | /** 21 | * Calls the named function, with the specified type encoding. 22 | */ 23 | id LKCallFunction(NSString *functionName, NSString *types, 24 | unsigned int argc, const id *args); 25 | /** 26 | * Gets the value of an instance variable, boxing it as necessary. 27 | */ 28 | id LKGetIvar(id receiver, NSString *name); 29 | 30 | /** 31 | * Sets the value of an instance variable, unboxing it as necessary. 32 | * 33 | * For object typed ivars, the existing value is released and the new value 34 | * is retained. 35 | */ 36 | BOOL LKSetIvar(id receiver, NSString *name, id value); 37 | 38 | /** 39 | * Creates and returns a "trampoline" Objective-C method implementation for a 40 | * method with the given type string. 41 | * 42 | * When invoked, this method implementation will call ASTForMethod() which will 43 | * look up the method's AST node using the slector and receiver's class, and 44 | * finally interpret the AST node using 45 | * -[LKMethod executeWithReciever:arguments:count:]. 46 | * 47 | * Note that the method IMPs returned by LKInterpreterMakeIMP can never be 48 | * freed (because they might be cached). 49 | */ 50 | IMP LKInterpreterMakeIMP(Class cls, const char *objctype); 51 | -------------------------------------------------------------------------------- /LanguageKit/LKLiteral.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LKLiteral : LKAST { 4 | /** String representation of value. Used because this can be a literal too 5 | * big to fit in a SmallInt. */ 6 | NSString * value; 7 | } 8 | + (id) literalFromString:(NSString*)aString; 9 | @end 10 | 11 | @interface LKNumberLiteral : LKLiteral {} 12 | /** 13 | * Creates a constant literal with the specified name. 14 | */ 15 | + (id) literalFromSymbol:(NSString*)aString; 16 | @end 17 | 18 | /** 19 | * Floating point literal value. 20 | */ 21 | @interface LKFloatLiteral : LKNumberLiteral @end 22 | 23 | @interface LKStringLiteral : LKLiteral {} 24 | @end 25 | -------------------------------------------------------------------------------- /LanguageKit/LKLiteral.m: -------------------------------------------------------------------------------- 1 | #import "LKLiteral.h" 2 | 3 | @implementation LKLiteral 4 | - (id) initWithString:(NSString*)aString 5 | { 6 | SUPERINIT; 7 | ASSIGN(value, aString); 8 | return self; 9 | } 10 | + (id) literalFromString:(NSString*)aString 11 | { 12 | return [[self alloc] initWithString:aString]; 13 | } 14 | - (NSString*) description 15 | { 16 | return value; 17 | } 18 | // No checking needed for literals - they are always semantically valid 19 | - (BOOL) check { return YES; } 20 | @end 21 | 22 | static NSDictionary *ObjCConstants; 23 | @implementation LKNumberLiteral 24 | + (void) initialize 25 | { 26 | if (self != [LKNumberLiteral class]) { return; } 27 | 28 | NSString *plist = [[NSBundle bundleForClass:self] 29 | pathForResource:@"ObjCConstants" ofType:@"plist"]; 30 | ObjCConstants = [NSDictionary dictionaryWithContentsOfFile:plist]; 31 | } 32 | + (id) literalFromSymbol:(NSString*)aString 33 | { 34 | NSString *val = [ObjCConstants objectForKey:aString]; 35 | if (nil == val) 36 | { 37 | [NSException raise:@"InvalidLiteral" 38 | format:@"Invalid symbolic constant %@", aString]; 39 | } 40 | return [LKNumberLiteral literalFromString:val]; 41 | } 42 | - (void*) compileWithGenerator: (id)aGenerator 43 | { 44 | return [aGenerator intConstant:value]; 45 | } 46 | @end 47 | 48 | @implementation LKFloatLiteral 49 | - (void*) compileWithGenerator: (id)aGenerator 50 | { 51 | return [aGenerator floatConstant: value]; 52 | } 53 | @end 54 | 55 | @implementation LKStringLiteral 56 | - (NSString*) description 57 | { 58 | return [NSString stringWithFormat:@"'%@'", value]; 59 | } 60 | - (void*) compileWithGenerator: (id)aGenerator 61 | { 62 | NSMutableString *escaped = [value mutableCopy]; 63 | [escaped replaceOccurrencesOfString:@"''" 64 | withString:@"'" 65 | options:0 66 | range:NSMakeRange(0, [escaped length])]; 67 | [escaped replaceOccurrencesOfString:@"\\\\" 68 | withString:@"\\s" 69 | options:0 70 | range:NSMakeRange(0, [escaped length])]; 71 | [escaped replaceOccurrencesOfString:@"\\n" 72 | withString:@"\n" 73 | options:0 74 | range:NSMakeRange(0, [escaped length])]; 75 | [escaped replaceOccurrencesOfString:@"\\t" 76 | withString:@"\t" 77 | options:0 78 | range:NSMakeRange(0, [escaped length])]; 79 | [escaped replaceOccurrencesOfString:@"\\s" 80 | withString:@"\\" 81 | options:0 82 | range:NSMakeRange(0, [escaped length])]; 83 | 84 | void *ret = [aGenerator stringConstant:escaped]; 85 | return ret; 86 | } 87 | @end 88 | -------------------------------------------------------------------------------- /LanguageKit/LKMessageSend.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a message send operation. 5 | */ 6 | @interface LKMessageSend : LKAST { 7 | /** Receiver of the message. */ 8 | id target; 9 | /** The message selector. */ 10 | NSString * selector; 11 | /** Array of AST nodes which evaluate to the message arguments. */ 12 | NSMutableArray * arguments; 13 | /** Array of possible type encodings for the method */ 14 | NSArray *type; 15 | } 16 | /** 17 | * Return a new message send. 18 | */ 19 | + (id) message; 20 | /** 21 | * Return a new message send with the specified selector. 22 | */ 23 | + (id) messageWithSelectorName:(NSString*)aSelector; 24 | /** 25 | * Return a new message send with the specified selector and arguments. 26 | */ 27 | + (id) messageWithSelectorName:(NSString*)aSelector 28 | arguments: (NSArray*)args; 29 | /** 30 | * Initialize with the specified selector. 31 | */ 32 | - (id) initWithSelectorName:(NSString*)aSelector; 33 | /** 34 | * Set the receiver of the message. 35 | */ 36 | - (void) setTarget:(id)anObject; 37 | /** 38 | * Add a component of the selector. 39 | */ 40 | - (void) addSelectorComponent:(NSString*)aSelector; 41 | /** 42 | * Add an argument. 43 | */ 44 | - (void) addArgument:(id)anObject; 45 | /** 46 | * Return all of the arguments of this message. 47 | */ 48 | - (NSArray*) arguments; 49 | /** 50 | * Return the selector. 51 | */ 52 | - (NSString*) selector; 53 | /** 54 | * Return the target 55 | */ 56 | - (id) target; 57 | @end 58 | /** 59 | * Send an array of messages to the same receiver. The receiver expression 60 | * will be evaluated once and each message will be sent to this receiver. 61 | */ 62 | @interface LKMessageCascade : LKAST { 63 | LKAST *receiver; 64 | NSMutableArray *messages; 65 | } 66 | + (LKMessageCascade*) messageCascadeWithTarget:(LKAST*) aTarget 67 | messages:(NSMutableArray*) messageArray; 68 | - (void) addMessage:(LKMessageSend*)aMessage; 69 | @end 70 | -------------------------------------------------------------------------------- /LanguageKit/LKMethod.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | /** 5 | * AST node representing a method. 6 | */ 7 | @interface LKMethod : LKAST 8 | /** Method signature - selector and names of arguments. */ 9 | @property (strong, nonatomic) LKMessageSend *signature; 10 | /** List of statements in this method. */ 11 | @property (strong, nonatomic) NSMutableArray *statements; 12 | /** 13 | * Return a new Method with the specified signature, locals and statements. 14 | */ 15 | + (id) methodWithSignature: (LKMessageSend*)aSignature 16 | locals: (NSMutableArray*)locals 17 | statements: (NSMutableArray*)statementList; 18 | /** 19 | * Initialise a new Method with the specified signature, locals and statements. 20 | */ 21 | - (id) initWithSignature: (LKMessageSend*)aSignature 22 | locals: (NSMutableArray*)localss 23 | statements: (NSMutableArray*)statementList; 24 | /** 25 | * Set the method signature for this method. 26 | */ 27 | - (void) setSignature:(LKMessageSend*)aSignature; 28 | /** 29 | * Returns the method's body 30 | */ 31 | - (NSString*) methodBody; 32 | /** 33 | * Returns YES if this is a class method. 34 | */ 35 | - (BOOL)isClassMethod; 36 | @end 37 | @interface LKInstanceMethod : LKMethod {} 38 | @end 39 | @interface LKClassMethod : LKMethod {} 40 | @end 41 | /** 42 | * A freestanding method is a method that is not attached to any class. It is 43 | * used in REPL mode, and might be useful for better support for prototypes. 44 | */ 45 | @interface LKFreestandingMethod : LKMethod {} 46 | @end 47 | -------------------------------------------------------------------------------- /LanguageKit/LKModule.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @class LKSubclass; 5 | @class LKCategory; 6 | 7 | /** 8 | * AST node representing a module - a set of classes and categories compiled 9 | * together. 10 | */ 11 | @interface LKModule : LKAST 12 | { 13 | /** Classes defined in this module. */ 14 | NSMutableArray * classes; 15 | /** Categories defined in this module. */ 16 | NSMutableArray * categories; 17 | /** Current pragmas */ 18 | NSMutableDictionary * pragmas; 19 | /** Manually-specified method types. */ 20 | NSMutableDictionary *typeOverrides; 21 | } 22 | /** 23 | * Return a new autoreleased module. 24 | */ 25 | + (id) module; 26 | /** 27 | * Add compile-time pragmas. 28 | */ 29 | - (void) addPragmas: (NSDictionary*)aDict; 30 | /** 31 | * Add a new class to this module. 32 | */ 33 | - (void) addClass: (LKSubclass*)aClass; 34 | /** 35 | * Add a new category to this module. 36 | */ 37 | - (void) addCategory: (LKCategory*)aCategory; 38 | /** 39 | * Returns an array of the types for a given selector name. 40 | */ 41 | - (NSArray*) typesForMethod:(NSString*)methodName; 42 | /** 43 | * Returns the classes in this module 44 | */ 45 | - (NSArray*) allClasses; 46 | /** 47 | * Returns the categories in this module 48 | */ 49 | - (NSArray*) allCategories; 50 | /** 51 | * Returns the pragmas in this module 52 | */ 53 | - (NSDictionary*) pragmas; 54 | @end 55 | 56 | /** 57 | * Notification posted when new classes have been compiled. 58 | */ 59 | extern NSString *LKCompilerDidCompileNewClassesNotification; 60 | 61 | 62 | -------------------------------------------------------------------------------- /LanguageKit/LKReturn.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a method return. 5 | */ 6 | @interface LKReturn : LKAST { 7 | /** Value to be returned. */ 8 | LKAST *ret; 9 | } 10 | /** 11 | * Autoreleased instance with an expression containing the value to return. 12 | */ 13 | + (id) returnWithExpr:(LKAST*)anExpression; 14 | /** 15 | * Initialise with an expression containing the value to return. 16 | */ 17 | - (id) initWithExpr:(LKAST*)anExpression; 18 | /** 19 | * Returns the return statement's expression AST node. 20 | */ 21 | - (LKAST*) expression; 22 | @end 23 | 24 | /** 25 | * AST node representing a block return. 26 | */ 27 | @interface LKBlockReturn : LKReturn {} 28 | @end 29 | -------------------------------------------------------------------------------- /LanguageKit/LKReturn.m: -------------------------------------------------------------------------------- 1 | #import "LKReturn.h" 2 | 3 | @implementation LKReturn 4 | + (id) returnWithExpr:(LKAST*)anExpression 5 | { 6 | return [[self alloc] initWithExpr: anExpression]; 7 | } 8 | - (id) initWithExpr:(LKAST*)anExpression 9 | { 10 | SUPERINIT; 11 | ASSIGN(ret, anExpression); 12 | return self; 13 | } 14 | - (BOOL)check 15 | { 16 | [ret setParent:self]; 17 | return [ret check]; 18 | } 19 | - (NSString*) description 20 | { 21 | return [NSString stringWithFormat:@"^%@.", ret]; 22 | } 23 | - (void*) compileWithGenerator: (id)aGenerator 24 | { 25 | void *retVal = [ret compileWithGenerator: aGenerator]; 26 | [aGenerator setReturn:retVal]; 27 | return retVal; 28 | } 29 | - (void) visitWithVisitor:(id)aVisitor 30 | { 31 | id tmp = [aVisitor visitASTNode:ret]; 32 | ASSIGN(ret, tmp); 33 | [ret visitWithVisitor:aVisitor]; 34 | } 35 | - (LKAST*) expression 36 | { 37 | return ret; 38 | } 39 | - (BOOL) isBranch 40 | { 41 | return YES; 42 | } 43 | @end 44 | 45 | @implementation LKBlockReturn 46 | - (void*) compileWithGenerator: (id)aGenerator 47 | { 48 | void *retVal = [ret compileWithGenerator: aGenerator]; 49 | [aGenerator blockReturn:retVal]; 50 | return retVal; 51 | } 52 | @end 53 | -------------------------------------------------------------------------------- /LanguageKit/LKSubclass.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a new class definition. 5 | */ 6 | @interface LKSubclass : LKAST { 7 | /** Name of this class. */ 8 | NSString * classname; 9 | /** Name of the superclass. */ 10 | NSString * superclass; 11 | /** Array of methods defined in this class. */ 12 | NSMutableArray * methods; 13 | /** Array of class variables defined for this class. */ 14 | NSMutableArray * cvars; 15 | /** Array of instance variables defined for this class. */ 16 | NSMutableArray * ivars; 17 | } 18 | /** 19 | * Return a new Subclass with the specified name, superclass and list of 20 | * instance variables and methods. The instance and class variable lists 21 | * should be strings and the method list is an array of AST nodes representing 22 | * methods. 23 | */ 24 | + (id) subclassWithName:(NSString*)aName 25 | superclassNamed:(NSString*)aClass 26 | cvars:(NSArray*)anIvarList 27 | ivars:(NSArray*)anotherIvarList 28 | methods:(NSArray*)aMethodList; 29 | /** 30 | * Returns the class name for the represented class. 31 | */ 32 | - (NSString*) classname; 33 | /** 34 | * Returns the superclass name for the class represented by this AST node. 35 | */ 36 | - (NSString*) superclassname; 37 | /** 38 | * Returns the methods 39 | */ 40 | - (NSArray*)methods; 41 | /** 42 | * Adds a new instance variable. 43 | */ 44 | - (void)addInstanceVariable: (NSString*)anIvar; 45 | /** 46 | * Returns an array of all of the names of instance variables. 47 | */ 48 | - (NSArray*)instanceVariables; 49 | /** 50 | * Returns an array of all of the names of class variables. 51 | */ 52 | - (NSArray*)classVariables; 53 | @end 54 | -------------------------------------------------------------------------------- /LanguageKit/LKSymbolRef.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * AST node representing a reference to a symbol (selector). 5 | */ 6 | @interface LKSymbolRef : LKAST 7 | { 8 | /** 9 | * The symbol. 10 | */ 11 | NSString *symbol; 12 | } 13 | /** Returns autoreleased reference for the specified symbol. */ 14 | + (id) referenceWithSymbol:(NSString*)sym; 15 | @end 16 | -------------------------------------------------------------------------------- /LanguageKit/LKSymbolRef.m: -------------------------------------------------------------------------------- 1 | #import "LKSymbolRef.h" 2 | 3 | @implementation LKSymbolRef 4 | - (id) initWithSymbol:(NSString*)sym 5 | { 6 | SUPERINIT; 7 | ASSIGN(symbol, sym); 8 | return self; 9 | } 10 | + (id) referenceWithSymbol:(NSString*)sym 11 | { 12 | return [[self alloc] initWithSymbol: sym]; 13 | } 14 | - (BOOL) check { return YES; } 15 | - (NSString*) description 16 | { 17 | return [NSString stringWithFormat:@"#%@", symbol]; 18 | } 19 | - (void*) compileWithGenerator: (id)aGenerator 20 | { 21 | return [aGenerator generateConstantSymbol:symbol]; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /LanguageKit/LKToken.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * LKToken implements a token for use in parsers. A token is a symbol or word 5 | * in a source program. The LKToken class stores this as a range and a pointer 6 | * to the source program, allowing it to be easily mapped back to the original. 7 | */ 8 | @interface LKToken : NSString { 9 | /** Source string. */ 10 | NSString *source; 11 | /** Range within the source string */ 12 | NSRange range; 13 | /** IMP used for looking up the character at the specified index in the 14 | * source string. */ 15 | unichar(*charAtIndex)(id, SEL, unsigned); 16 | } 17 | /** 18 | * Create a token from a range in the specified source string. 19 | */ 20 | + (LKToken*) tokenWithRange:(NSRange)aRange inSource:(NSString*)aString; 21 | /** 22 | * Returns the location in the original program of this token. 23 | */ 24 | - (NSRange) sourceLocation; 25 | /** 26 | * Returns the source code string from which this token was generated. 27 | */ 28 | - (NSString*) sourceDocument; 29 | @end 30 | -------------------------------------------------------------------------------- /LanguageKit/LKToken.m: -------------------------------------------------------------------------------- 1 | #import "LKToken.h" 2 | #import 3 | 4 | typedef unichar(*CIMP)(id, SEL, unsigned); 5 | 6 | @implementation NSString (Token) 7 | - (NSRange) sourceLocation 8 | { 9 | return NSMakeRange(0, 0); 10 | } 11 | @end 12 | 13 | @interface LKCompositeToken : NSString 14 | { 15 | NSString *str; 16 | NSRange range; 17 | } 18 | - (id)initWithStart: (NSString*)s end: (NSString*)e; 19 | @end 20 | @implementation LKCompositeToken 21 | - (id)initWithStart: (NSString*)s end: (NSString*)e 22 | { 23 | self = [super init]; 24 | NSRange r = [e sourceLocation]; 25 | str = [NSString stringWithFormat: @"%@%@", s, e]; 26 | range.location = [s sourceLocation].location; 27 | range.length = r.location - range.location + r.length; 28 | return self; 29 | } 30 | - (NSString*)stringByAppendingString: (NSString*)other 31 | { 32 | NSRange secondRange = [other sourceLocation]; 33 | NSUInteger end = secondRange.location + secondRange.length; 34 | if (end < range.location + range.length) 35 | { 36 | return [super stringByAppendingString: other]; 37 | } 38 | return [[LKCompositeToken alloc] initWithStart: self end: other]; 39 | } 40 | - (NSUInteger) length 41 | { 42 | return [str length]; 43 | } 44 | - (unichar) characterAtIndex:(NSUInteger)index 45 | { 46 | return [str characterAtIndex: index]; 47 | } 48 | - (NSRange) sourceLocation 49 | { 50 | return range; 51 | } 52 | @end 53 | 54 | 55 | @implementation LKToken 56 | - (LKToken*) initWithRange:(NSRange)aRange inSource:(NSString*)aString 57 | { 58 | SUPERINIT; 59 | charAtIndex = (CIMP)[aString methodForSelector:@selector(characterAtIndex:)]; 60 | ASSIGN(source, aString); 61 | range = aRange; 62 | return self; 63 | } 64 | + (LKToken*) tokenWithRange:(NSRange)aRange inSource:(NSString*)aString 65 | { 66 | return [[LKToken alloc] initWithRange:aRange inSource:aString]; 67 | } 68 | - (NSUInteger) length 69 | { 70 | return range.length; 71 | } 72 | - (unichar) characterAtIndex:(NSUInteger)index 73 | { 74 | return charAtIndex(source, @selector(characterAtIndex:), index + 75 | range.location); 76 | } 77 | - (NSRange) sourceLocation 78 | { 79 | return range; 80 | } 81 | - (NSString*) sourceDocument 82 | { 83 | return source; 84 | } 85 | - (NSString*)stringByAppendingString: (NSString*)str 86 | { 87 | NSRange secondRange = [str sourceLocation]; 88 | NSUInteger end = secondRange.location + secondRange.length; 89 | if (end < range.location + range.length) 90 | { 91 | return [super stringByAppendingString: str]; 92 | } 93 | return [[LKCompositeToken alloc] initWithStart: self end: str]; 94 | } 95 | @end 96 | -------------------------------------------------------------------------------- /LanguageKit/LKTypeHelpers.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | * Functions for working with Objective-C type strings 5 | */ 6 | 7 | void LKSkipQualifiers(const char **typestr); 8 | void LKNextType(const char **typestr); 9 | int LKCountObjCTypes(const char *objctype); 10 | -------------------------------------------------------------------------------- /LanguageKit/LKTypeHelpers.m: -------------------------------------------------------------------------------- 1 | #import "LKTypeHelpers.h" 2 | 3 | void LKSkipQualifiers(const char **typestr) 4 | { 5 | char c = **typestr; 6 | while ((c >= '0' && c <= '9') || c == 'r' || c == 'n' || c == 'N' || 7 | c == 'o' || c == 'O' || c == 'R' || c == 'V') 8 | { 9 | (*typestr)++; 10 | c = **typestr; 11 | } 12 | } 13 | 14 | #define SKIPNAME \ 15 | while (**typestr != '=')\ 16 | {\ 17 | (*typestr)++;\ 18 | }\ 19 | (*typestr)++ 20 | 21 | void LKNextType(const char **typestr) 22 | { 23 | LKSkipQualifiers(typestr); 24 | switch (**typestr) 25 | { 26 | case '{': 27 | (*typestr)++; 28 | SKIPNAME; 29 | while (**typestr != '}') 30 | { 31 | LKNextType(typestr); 32 | } 33 | (*typestr)++; 34 | break; 35 | case '(': 36 | (*typestr)++; 37 | SKIPNAME; 38 | while (**typestr != ')') 39 | { 40 | LKNextType(typestr); 41 | } 42 | (*typestr)++; 43 | break; 44 | case '[': 45 | (*typestr)++; 46 | while (**typestr != '[') 47 | { 48 | LKNextType(typestr); 49 | } 50 | (*typestr)++; 51 | break; 52 | case '^': 53 | (*typestr)++; 54 | LKNextType(typestr); 55 | break; 56 | default: 57 | (*typestr)++; 58 | } 59 | } 60 | 61 | int LKCountObjCTypes(const char *objctype) 62 | { 63 | if (NULL == objctype) 64 | { 65 | return 0; 66 | } 67 | int count = 0; 68 | while (*objctype != '\0') 69 | { 70 | LKNextType(&objctype); 71 | LKSkipQualifiers(&objctype); 72 | count++; 73 | } 74 | return count; 75 | } 76 | 77 | -------------------------------------------------------------------------------- /LanguageKit/LKVariableDecl.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class LKToken; 4 | 5 | @interface LKVariableDecl : LKAST { 6 | LKToken *variableName; 7 | } 8 | + (LKVariableDecl*) variableDeclWithName:(LKToken*) declName; 9 | - (NSString*)name; 10 | @end 11 | -------------------------------------------------------------------------------- /LanguageKit/LKVariableDecl.m: -------------------------------------------------------------------------------- 1 | #import "LKVariableDecl.h" 2 | #import "LKToken.h" 3 | #import "Runtime/LKObject.h" 4 | #import 5 | 6 | @implementation LKVariableDecl 7 | - (LKVariableDecl*) initWithName: (LKToken*) declName 8 | { 9 | SUPERINIT; 10 | ASSIGN(variableName, declName); 11 | return self; 12 | } 13 | + (LKVariableDecl*) variableDeclWithName:(LKToken*) declName 14 | { 15 | return [[self alloc] initWithName:declName]; 16 | } 17 | - (NSString*) description 18 | { 19 | return [NSString stringWithFormat:@"var %@", variableName]; 20 | } 21 | - (void) setParent:(LKAST*)aParent 22 | { 23 | [super setParent:aParent]; 24 | LKSymbol *sym = [LKSymbol new]; 25 | [sym setName: variableName]; 26 | [sym setTypeEncoding: NSStringFromRuntimeString(@encode(LKObject))]; 27 | [sym setScope: LKSymbolScopeLocal]; 28 | [symbols addSymbol: sym]; 29 | } 30 | - (NSString*)name 31 | { 32 | return (NSString*)variableName; 33 | } 34 | - (BOOL) check { return YES; } 35 | - (void*) compileWithGenerator: (id)aGenerator 36 | { 37 | return NULL; 38 | } 39 | @end 40 | -------------------------------------------------------------------------------- /LanguageKit/LanguageKit.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | -------------------------------------------------------------------------------- /LanguageKit/ObjCConstants.plist: -------------------------------------------------------------------------------- 1 | { 2 | NSViewNotSizable = 0; 3 | NSViewMinXMargin = 1; 4 | NSViewWidthSizable = 2; 5 | NSViewMaxXMargin = 4; 6 | NSViewMinYMargin = 8; 7 | NSViewHeightSizable = 16; 8 | NSViewMaxYMargin = 32; 9 | 10 | NSUTF8StringEncoding = 4; 11 | 12 | NSItalicFontMask = 1; 13 | NSBoldFontMask = 2; 14 | NSUnboldFontMask = 4; 15 | NSNonStandardCharacterSetFontMask = 8; 16 | NSNarrowFontMask = 16; 17 | NSExpandedFontMask = 32; 18 | NSCondensedFontMask = 64; 19 | NSSmallCapsFontMask = 128; 20 | NSPosterFontMask = 256; 21 | NSCompressedFontMask = 512; 22 | NSFixedPitchFontMask = 1024; 23 | NSUnitalicFontMask = 16777216; 24 | } 25 | -------------------------------------------------------------------------------- /LanguageKit/README: -------------------------------------------------------------------------------- 1 | LanguageKit 2 | =========== 3 | 4 | LanguageKit provides the abstract syntax tree and compilation framework for 5 | Étoilé Pragmatic Smalltalk and EScript. LanguageKit is split into three main 6 | components: 7 | 8 | - The core LanguageKit framework provides the abstract syntax tree structure 9 | that front ends (such as Pragmatic Smalltalk) construct and manipulate. It 10 | also contains an AST interpreter. 11 | - The Runtime subframework provides a runtime library for code generated by 12 | LanguageKit. This sits on top of the Objective-C runtime and provides extra 13 | features, such as non-local returns and small integers. 14 | - The CodeGen framework uses LLVM to generate optimised native code from 15 | LanguageKit abstract syntax trees. 16 | 17 | Code Generation Overview 18 | ------------------------ 19 | 20 | The code generation framework generates code that is ABI-compatible with 21 | Objective-C. Classes, methods, and blocks use the same underlying 22 | representation as Objective-C. 23 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/BigInt.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "LKObject.h" 3 | #include 4 | 5 | @interface BigInt : NSNumber { 6 | @public 7 | /** 8 | * Value for this object. Public so it can be accessed from others to 9 | * slightly lower the cost of operations on BigInts. 10 | */ 11 | mpz_t v; 12 | } 13 | + (BigInt*) bigIntWithCString:(const char*) aString; 14 | + (BigInt*) bigIntWithLongLong:(long long)aVal; 15 | + (BigInt*) bigIntWithLong:(long)aVal; 16 | + (BigInt*) bigIntWithUnsignedLong:(unsigned long)aVal; 17 | + (BigInt*) bigIntWithMP:(mpz_t)aVal; 18 | @end 19 | #ifndef OBJC_SMALL_OBJECT_SHIFT 20 | #define OBJC_SMALL_OBJECT_SHIFT ((sizeof(id) == 4) ? 1 : 3) 21 | #endif 22 | 23 | static inline LKObject LKObjectFromNSInteger(NSInteger integer) 24 | { 25 | if((integer << OBJC_SMALL_OBJECT_SHIFT >> OBJC_SMALL_OBJECT_SHIFT) != integer) 26 | { 27 | return LKObjectFromObject([BigInt bigIntWithLongLong: (long long)integer]); 28 | } 29 | else 30 | { 31 | return LKObjectFromObject((__bridge id)(void*)((integer << OBJC_SMALL_OBJECT_SHIFT) | 1)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/BlockClosure+debug.m: -------------------------------------------------------------------------------- 1 | #define __XSI_VISIBLE 600 2 | #import "BlockClosure.h" 3 | #import "BlockContext.h" 4 | #include 5 | #include 6 | 7 | @interface LKStackTraceArray : NSArray { 8 | @public 9 | int count; 10 | id *buffer; 11 | } 12 | @end 13 | @implementation LKStackTraceArray 14 | - (NSUInteger)count 15 | { 16 | return count; 17 | } 18 | - (id)objectAtIndex: (NSUInteger)index 19 | { 20 | if (index > count) { return nil; } 21 | return buffer[index]; 22 | } 23 | - (void)dealloc 24 | { 25 | free(buffer); 26 | [super dealloc]; 27 | } 28 | @end 29 | 30 | static __thread volatile char fellOffStack; 31 | static __thread ucontext_t sigretcontext; 32 | 33 | static void segv(int sig, siginfo_t *info, void *addr) 34 | { 35 | fellOffStack = 1; 36 | setcontext(&sigretcontext); 37 | } 38 | 39 | static int getStackDirection(int *a) 40 | { 41 | int b; 42 | return a - &b > 0 ? 1 : -1; 43 | } 44 | 45 | typedef struct 46 | { 47 | @defs(BlockClosure); 48 | } *BlockClosureIvars; 49 | 50 | char *LanguageKitStackTopAddress; 51 | 52 | static Class StackContextClass; 53 | static Class RetainedStackContextClass; 54 | static Class StackBlockClosureClass; 55 | @implementation BlockClosure (Debug) 56 | + (void)load 57 | { 58 | StackContextClass = [StackContext class]; 59 | RetainedStackContextClass = [RetainedStackContext class]; 60 | StackBlockClosureClass = [StackBlockClosure class]; 61 | } 62 | + (NSArray*)stackContexts; 63 | { 64 | int a; 65 | ptrdiff_t offset = (ptrdiff_t)&(((BlockClosureIvars)0)->context); 66 | offset -= (ptrdiff_t)&(((BlockClosureIvars)0)->isa); 67 | 68 | int direction = getStackDirection(&a); 69 | 70 | id *buffer = calloc(8, sizeof(id)); 71 | volatile int count = 0; 72 | volatile int buffersize = 8; 73 | 74 | char *foundContext = (char*)&a; 75 | // Set the SegV handler. 76 | struct sigaction new; 77 | new.sa_sigaction = segv; 78 | new.sa_flags = SA_SIGINFO; 79 | sigemptyset (&new.sa_mask); 80 | struct sigaction old; 81 | sigaction(SIGSEGV, &new, &old); 82 | fellOffStack = 0; 83 | // Save the context. We'll return here after the segfault 84 | getcontext(&sigretcontext); 85 | // This flag is set to 1 if a SegV occurs 86 | while(!fellOffStack) 87 | { 88 | if (((Class)((id)foundContext)->class_pointer == StackContextClass 89 | || (Class)((id)foundContext)->class_pointer == RetainedStackContextClass)) 90 | { 91 | if ((Class)((id)(foundContext - offset))->class_pointer == StackBlockClosureClass) 92 | { 93 | // Ignore the BlockClosure object for now. 94 | } 95 | else 96 | { 97 | if (count >= buffersize) 98 | { 99 | buffersize *= 2; 100 | buffer = realloc(buffer, buffersize); 101 | } 102 | buffer[count++] = (id)foundContext; 103 | } 104 | } 105 | // Walk up the stack until we fall off 106 | foundContext += direction; 107 | } 108 | // Reset the SegV handler. 109 | sigaction(SIGSEGV, &old, NULL); 110 | LKStackTraceArray *array = [[[LKStackTraceArray alloc] init] autorelease]; 111 | array->count = count; 112 | array->buffer = buffer; 113 | return array; 114 | } 115 | @end 116 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/BlockClosure.h: -------------------------------------------------------------------------------- 1 | #import 2 | #include 3 | 4 | extern NSString *LKSmalltalkBlockNonLocalReturnException; 5 | 6 | @class BlockContext; 7 | 8 | @interface BlockClosure : NSObject { 9 | @public 10 | IMP function; 11 | @protected 12 | /** 13 | * Number of arguments. Used for checking when calling -value. 14 | */ 15 | int32_t args; 16 | /** The context for this block. */ 17 | BlockContext *context; 18 | } 19 | - (id)blockContext; 20 | - (int32_t) argumentCount; 21 | - (id) value; 22 | - (id) value:(id)a1; 23 | - (id) value:(id)a1 value:(id)a2; 24 | - (id) value:(id)a1 value:(id)a2 value:(id)a3; 25 | - (id) value:(id)a1 value:(id)a2 value:(id)a3 value:(id)a4; 26 | @end 27 | 28 | @interface StackBlockClosure : BlockClosure {} 29 | @end 30 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/BlockClosure.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "BlockClosure.h" 3 | #import "BlockContext.h" 4 | #include 5 | 6 | NSString *LKSmalltalkBlockNonLocalReturnException = 7 | @"LKSmalltalkBlockNonLocalReturnException"; 8 | @interface _NSBlock : NSObject 9 | -value; 10 | @end 11 | 12 | @implementation _NSBlock (BlockClosure) 13 | - (id) whileTrue:(id)anotherBlock 14 | { 15 | id last = nil; 16 | for (id ret = [self value] ; 17 | (uintptr_t)ret != 1 && [ret boolValue] ; 18 | ret = [self value]) 19 | { 20 | last = [anotherBlock value]; 21 | } 22 | return last; 23 | } 24 | @end 25 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/BlockContext.h: -------------------------------------------------------------------------------- 1 | @interface BlockContext : NSObject { 2 | @public 3 | BlockContext *parent; 4 | int count; 5 | char **symbolTable; 6 | id objects[0]; 7 | } 8 | - (BOOL)setValue: (id)aValue forSymbol: (NSString*)aSymbol; 9 | - (id)valueForSymbol: (NSString*)aSymbol; 10 | @end 11 | 12 | @interface StackContext : BlockContext {} 13 | @end 14 | 15 | @interface RetainedStackContext : StackContext {} 16 | @end 17 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/BoxedFloat.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface BoxedFloat : NSObject 4 | { 5 | @public 6 | double value; 7 | } 8 | + (BoxedFloat*) boxedFloatWithCString:(const char*) aString; 9 | + (BoxedFloat*) boxedFloatWithDouble:(double)aVal; 10 | + (BoxedFloat*) boxedFloatWithFloat:(float)aVal; 11 | @end 12 | 13 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | # We redefine the project name since the framework name doesn't match the name 7 | # of the project directory (Runtime) 8 | PROJECT_NAME = LanguageKitRuntime 9 | 10 | FRAMEWORK_NAME = ${PROJECT_NAME} 11 | 12 | LIBRARIES_DEPEND_UPON += -lgmp $(FND_LIBS) $(OBJC_LIBS) $(SYSTEM_LIBS) 13 | 14 | 15 | ${FRAMEWORK_NAME}_CPPFLAGS += -D_POSIX_C_SOURCE=199309 -D_BSD_SOURCE 16 | ${FRAMEWORK_NAME}_OBJCFLAGS += -std=c99 -fexceptions -fobjc-exceptions 17 | ${FRAMEWORK_NAME}_CFLAGS += -std=c99 -fexceptions 18 | 19 | ifeq ($(broken_ctype), yes) 20 | LIBRARIES_DEPEND_UPON += -licuuc 21 | ${FRAMEWORK_NAME}_OBJCFLAGS += -std=c99 -fexceptions -fobjc-exceptions -DBROKEN_CTYPE 22 | endif 23 | 24 | ${FRAMEWORK_NAME}_OBJC_FILES = \ 25 | BigInt.m\ 26 | BlockClosure.m\ 27 | BoxedFloat.m\ 28 | NSValue+structs.m\ 29 | LanguageKitExceptions.m\ 30 | OverflowHandler.m\ 31 | NSString+conversions.m\ 32 | Symbol.m 33 | 34 | ${FRAMEWORK_NAME}_OBJ_FILES = MsgSendSmallInt.o 35 | 36 | ${FRAMEWORK_NAME}_HEADER_FILES = \ 37 | BigInt.h\ 38 | LKObject.h\ 39 | BlockClosure.h\ 40 | Symbol.h 41 | 42 | include $(GNUSTEP_MAKEFILES)/framework.make 43 | -include ../../../etoile.make 44 | -include ../../../documentation.make 45 | 46 | MsgSendSmallInt.o: 47 | @echo " Compiling small int messages..." 48 | @clang -c -ftrapv `gnustep-config --objc-flags` ${${FRAMEWORK_NAME}_OBJCFLAGS} MsgSendSmallInt.m -o MsgSendSmallInt.o -DSTATIC_COMPILE 49 | 50 | before-clean:: 51 | @rm -f MsgSendSmallInt.o MsgSendSmallInt.d 52 | 53 | before-distclean:: before-clean 54 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/LKObject.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | /** 5 | * If we have small object support in the runtime, then we just use it and get 6 | * rid of all of the hackery. 7 | */ 8 | #pragma clang diagnostic ignored "-Wdeprecated-objc-pointer-introspection" 9 | #ifdef OBJC_SMALL_OBJECT_SHIFT 10 | 11 | @class NSSmallInt; 12 | 13 | typedef NSSmallInt* SmallInt; 14 | 15 | typedef id LKObject; 16 | 17 | #define LKOBJECT(x) x 18 | 19 | __attribute__((unused)) 20 | static inline BOOL LKObjectIsSmallInt(LKObject obj) 21 | { 22 | return ((NSInteger)obj & OBJC_SMALL_OBJECT_MASK) != 0; 23 | } 24 | 25 | __attribute__((unused)) 26 | static id LKObjectToId(LKObject obj) 27 | { 28 | return obj; 29 | } 30 | 31 | __attribute__((unused)) 32 | static inline BOOL LKObjectIsObject(LKObject obj) 33 | { 34 | return ((NSInteger)obj & OBJC_SMALL_OBJECT_MASK) == 0; 35 | } 36 | 37 | __attribute__((unused)) 38 | static inline NSInteger NSIntegerFromSmallInt(LKObject smallInt) 39 | { 40 | return [smallInt integerValue]; 41 | } 42 | __attribute__((unused)) 43 | static inline LKObject LKObjectFromObject(id obj) 44 | { 45 | return obj; 46 | } 47 | 48 | 49 | #else 50 | 51 | /** 52 | * LKObject.h defines the type used for LanguageKit object and some functions 53 | * for mapping these to and from Objective-C values. Objects in LanguageKit 54 | * follow the Smalltalk model. They are either object pointers or small 55 | * integer values stored in the most significant sizeof(void*)-1 bits of the 56 | * pointer. 57 | * 58 | * Note: In future versions of LanguageKit, on 64-bit platforms, LK objects may 59 | * be modified to contain 62-bit integers, 32-bit floats, or pointers. 60 | */ 61 | 62 | typedef NSInteger SmallInt; 63 | 64 | typedef __attribute__ ((__transparent_union__)) union 65 | { 66 | /** 67 | * The object value. 68 | */ 69 | __unsafe_unretained id object; 70 | SmallInt smallInt; 71 | } LKObject; 72 | 73 | 74 | #define LKOBJECT(x) (*(__bridge LKObject*)&x) 75 | 76 | __attribute__((unused)) 77 | static inline BOOL LKObjectIsSmallInt(LKObject obj) 78 | { 79 | return (obj.smallInt & 1); 80 | } 81 | 82 | __attribute__((unused)) 83 | static id LKObjectToId(LKObject obj) 84 | { 85 | if (1 == (obj.smallInt & 1)) 86 | { 87 | return nil; 88 | } 89 | return obj.object; 90 | } 91 | 92 | __attribute__((unused)) 93 | static inline BOOL LKObjectIsObject(LKObject obj) 94 | { 95 | return (obj.smallInt & 1) == 0; 96 | } 97 | 98 | __attribute__((unused)) 99 | static inline NSInteger NSIntegerFromSmallInt(LKObject smallInt) 100 | { 101 | NSCAssert(smallInt.smallInt & 1, @"Not a SmallInt!"); 102 | return smallInt.smallInt >> 1; 103 | } 104 | 105 | __attribute__((unused)) 106 | static inline LKObject LKObjectFromObject(id obj) 107 | { 108 | LKObject o; 109 | o.object = obj; 110 | return o; 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/NSString+conversions.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation NSString (Conversions) 4 | - (unsigned long long)unsignedLongLongValue 5 | { 6 | return (unsigned long long)[self longLongValue]; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/NSValue+structs.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | id LKBoxValue(void *bytes, const char *typeEncoding) 4 | { 5 | if (NULL == bytes) 6 | { 7 | return nil; 8 | } 9 | return [NSValue valueWithBytes:bytes objCType:typeEncoding]; 10 | } 11 | void LKUnboxValue(id boxed, void *buffer, const char *typeEncoding) 12 | { 13 | if (nil == boxed) 14 | { 15 | NSUInteger size, align; 16 | NSGetSizeAndAlignment(typeEncoding, &size, &align); 17 | memset(buffer, 0, size); 18 | } 19 | assert(strcmp(typeEncoding, [boxed objCType]) == 0); 20 | return [boxed getValue: buffer]; 21 | } 22 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/OverflowHandler.m: -------------------------------------------------------------------------------- 1 | #import "BigInt.h" 2 | 3 | @interface BigInt (Private) 4 | - (LKObject)plus: (BigInt*)other; 5 | - (LKObject)mul: (BigInt*)other; 6 | @end 7 | 8 | static char *ops[] = {"add", "subtract", "multiply"}; 9 | 10 | long long smalltalk_overflow_handler(long long val, long long otherval, char op, 11 | char width) 12 | { 13 | switch(op>>1) 14 | { 15 | case 1: 16 | { 17 | LKObject bigInt = 18 | [[BigInt bigIntWithLongLong:((long long)val) >> 1] 19 | plus: [BigInt bigIntWithLongLong:((long long)otherval) >> 1]]; 20 | return (long long)*(intptr_t*)&bigInt; 21 | } 22 | case 3: 23 | { 24 | LKObject bigInt = [[BigInt bigIntWithLongLong:((long long)val) >> 1] 25 | mul:[BigInt bigIntWithLongLong:((long long)otherval) >> 1]]; 26 | // We set the low bit here so that we can use XOR to set it in the 27 | return (long long)((*(intptr_t*)&bigInt) | 1); 28 | } 29 | } 30 | // Should never be reached. 31 | char *opname = ops[(op >>1) - 1]; 32 | char *sign = op & 1 ? "signed" : "unsigned"; 33 | fprintf(stderr, "Unexpected integer overflow in Smalltalk code!\n" 34 | "Op %s %s on %d-bit values, Aborting!\n", 35 | sign, opname, (int)width); 36 | abort(); 37 | } 38 | 39 | long long (*__overflow_handler)(long long a, long long b, char op, char width) 40 | = smalltalk_overflow_handler; 41 | 42 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/Symbol.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #ifndef __has_feature // Optional. 4 | #define __has_feature(x) 0 // Compatibility with non-clang compilers. 5 | #endif 6 | 7 | #ifndef NS_RETURNS_RETAINED 8 | #if __has_feature(attribute_ns_returns_retained) 9 | #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) 10 | #else 11 | #define NS_RETURNS_RETAINED 12 | #endif 13 | #endif 14 | 15 | 16 | @interface Symbol : NSObject 17 | { 18 | SEL selector; 19 | } 20 | + (id) SymbolForString:(NSString*)aSymbol NS_RETURNS_RETAINED; 21 | + (id) SymbolForCString:(const char*)aSymbol NS_RETURNS_RETAINED; 22 | + (id) SymbolForSelector:(SEL) aSelector NS_RETURNS_RETAINED; 23 | 24 | - (id) copyWithZone: (NSZone*)aZone; 25 | - (id) initWithSelector:(SEL) aSelector; 26 | - (id) stringValue; 27 | - (SEL) selValue; 28 | @end 29 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/Symbol.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "Symbol.h" 4 | 5 | @implementation Symbol 6 | + (id) SymbolForString:(NSString*)aSymbol 7 | { 8 | return [self SymbolForCString: [aSymbol UTF8String]]; 9 | } 10 | + (id) SymbolForCString:(const char*)aSymbol 11 | { 12 | return [[Symbol alloc] initWithSelector:sel_getUid(aSymbol)]; 13 | } 14 | + (id) SymbolForSelector:(SEL) aSelector 15 | { 16 | return [[Symbol alloc] initWithSelector:aSelector]; 17 | } 18 | - (id) copyWithZone: (NSZone*) aZone 19 | { 20 | return [self retain]; 21 | } 22 | - (id) initWithSelector:(SEL) aSelector 23 | { 24 | SELFINIT 25 | selector = aSelector; 26 | return self; 27 | } 28 | - (id) stringValue 29 | { 30 | return NSStringFromSelector(selector); 31 | } 32 | - (SEL) selValue 33 | { 34 | return selector; 35 | } 36 | - (NSString*)description 37 | { 38 | return [@"#" stringByAppendingString: NSStringFromSelector(selector)]; 39 | } 40 | @end 41 | -------------------------------------------------------------------------------- /LanguageKit/Runtime/unwind.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Typedef to allow prototypes from EH documentation to work unmodified 3 | */ 4 | typedef uint64_t uint64; 5 | 6 | /** 7 | * Standard exception handling definitions which don't seem to be in a header. 8 | */ 9 | typedef enum { 10 | _URC_NO_REASON = 0, 11 | _URC_FOREIGN_EXCEPTION_CAUGHT = 1, 12 | _URC_FATAL_PHASE2_ERROR = 2, 13 | _URC_FATAL_PHASE1_ERROR = 3, 14 | _URC_NORMAL_STOP = 4, 15 | _URC_END_OF_STACK = 5, 16 | _URC_HANDLER_FOUND = 6, 17 | _URC_INSTALL_CONTEXT = 7, 18 | _URC_CONTINUE_UNWIND = 8 19 | } _Unwind_Reason_Code; 20 | 21 | typedef void (*_Unwind_Exception_Cleanup_Fn) 22 | (_Unwind_Reason_Code reason, 23 | void *exc); 24 | 25 | struct _Unwind_Exception { 26 | uint64 exception_class; 27 | _Unwind_Exception_Cleanup_Fn exception_cleanup; 28 | uint64 private_1; 29 | uint64 private_2; 30 | }; 31 | 32 | _Unwind_Reason_Code _Unwind_RaiseException 33 | ( struct _Unwind_Exception *exception_object ); 34 | 35 | void _Unwind_Resume (struct _Unwind_Exception *exception_object); 36 | 37 | struct _Unwind_Context; 38 | uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); 39 | void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t); 40 | uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); 41 | uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); 42 | 43 | typedef int _Unwind_Action; 44 | static const _Unwind_Action _UA_SEARCH_PHASE = 1; 45 | static const _Unwind_Action _UA_CLEANUP_PHASE = 2; 46 | static const _Unwind_Action _UA_HANDLER_FRAME = 4; 47 | static const _Unwind_Action _UA_FORCE_UNWIND = 8; 48 | 49 | -------------------------------------------------------------------------------- /Smalltalk/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007, David Chisnall 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | * Neither the name of the Étoilé project, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | 16 | 17 | -------------------------------------------------------------------------------- /Smalltalk/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | 7 | SUBPROJECTS = Support 8 | # 9 | # Library 10 | # 11 | VERSION = 0.7 12 | BUNDLE_NAME = Smalltalk 13 | BUNDLE_EXTENSION = .language 14 | BUNDLE_INSTALL_DIR = $(GNUSTEP_BUNDLES)/LanguageKit 15 | 16 | ${BUNDLE_NAME}_PRINCIPAL_CLASS = SmalltalkCompiler 17 | 18 | ${BUNDLE_NAME}_OBJC_FILES = \ 19 | smalltalk.m\ 20 | SmalltalkCompiler.m\ 21 | SmalltalkParser.m 22 | 23 | ${BUNDLE_NAME}_OBJCFLAGS = -std=c99 -g -Wno-unused-value 24 | ${BUNDLE_NAME}_LDFLAGS += -g -lEtoileFoundation -lLanguageKit \ 25 | -lSmalltalkSupport 26 | ${BUNDLE_NAME}_CFLAGS += -Wno-implicit -g 27 | 28 | include $(GNUSTEP_MAKEFILES)/aggregate.make 29 | include $(GNUSTEP_MAKEFILES)/bundle.make 30 | -include ../../etoile.make 31 | 32 | smalltalk.h: smalltalk.m 33 | 34 | smalltalk.m: smalltalk.y lempar.c lemon 35 | @echo Generating parser... 36 | @./lemon smalltalk.y ; mv smalltalk.c smalltalk.m 37 | 38 | lemon: lemon.c 39 | @echo Compiling parser generator 40 | @$(CC) lemon.c -o lemon 41 | 42 | clean:: 43 | @rm -f smalltalk.h smalltalk.m smalltalk.out lemon 44 | 45 | test: 46 | @cd Tests && sh runall.sh -q 47 | -------------------------------------------------------------------------------- /Smalltalk/README: -------------------------------------------------------------------------------- 1 | 2 | Differences to traditional Smalltalk environments 3 | ------------------------------------------------- 4 | 5 | * The OO environment is different to the traditional ST-80 environment. 6 | 7 | * Smalltalk traditionally has an algebraic type system - objects are algebras 8 | defined by an implicit or explicit signature. C, on the other hand, has a 9 | structural type system, where objects are defined by their in-memory 10 | layout. Objective-C incorporates both of these, which has a few issues with 11 | Smalltalk. Some methods will return something that is not an object in the 12 | Smalltalk sense of the word. These will be automatically boxed when calling 13 | other methods. The major issue Smalltalk programmers are likely to 14 | encounter is that implementing methods with the same name as an Objective-C 15 | method will result in that method inheriting the Objective-C method's 16 | structural type signature. This means that it will be limited to returning 17 | types that can be mapped to the relevant C types and will only accept 18 | arguments that have the correct C type. For example, the `count` is define 19 | by NSArray as returning an int. If you return an object, it must respond to 20 | `intValue` and return a C integer. 21 | 22 | * Sending messages to nil *always* directly returns nil. In the case of 23 | messages which would return something other than an object, this means a 24 | block of memory of the correct return size initialised with zeroes, e.g. the 25 | integer value 0 or a structure containing 0 for all elements. 26 | 27 | Especially the following things do not work: 28 | * nil = anObject --> will never work, use anObject == nil instead! 29 | * nil log. --> will not log anything. Consider using the 30 | ETTranscript instead. 31 | 32 | * In the Objective-C documentation, method names are often written 33 | differently to the usual Smalltalk conventions: 34 | 35 | Smalltalk | Objective-C 36 | -----------------------|----------------------- 37 | Car>>driveFrom:To: | -[Car driveFrom:To:] 38 | Car class>>defaultCar | +[Car defaultCar] 39 | 40 | * The default method return value is self, but only in the case of . 41 | 42 | * Basic classes and methods 43 | 44 | * Most of the Smalltalk-80 classes do not exist directly, although they have 45 | analogues in the OpenStep library. Literals construct the OpenStep versions 46 | such as NSString for string literals and NSMutableArray for arrays. 47 | 48 | * Small integers are implemented in C and compiled to LLVM bitcode. If you 49 | want to add methods to SmallInt you can do so in two ways. If SmallInt 50 | doesn't implement a method, the value will be promoted to a BigInt and the 51 | method retried, so categories on BigInt will work (although they will be 52 | slow). Alternatively, you can modify the MsgSendSmallInt.m file, recompile 53 | it with clang, and include it with your code. 54 | 55 | * There's a Transcript class called ETTranscript, which has the class 56 | methods show: and cr. 57 | 58 | * There are no explicit Boolean classes, ifTrue: and the like can 59 | be called on integers. An integer is considered true iff it's 60 | not zero. Other classes may implement ifTrue: and friends as normal. 61 | -------------------------------------------------------------------------------- /Smalltalk/SmalltalkCompiler.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface SmalltalkCompiler : LKCompiler {} 4 | @end 5 | -------------------------------------------------------------------------------- /Smalltalk/SmalltalkCompiler.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "SmalltalkCompiler.h" 3 | #import "SmalltalkParser.h" 4 | 5 | @implementation SmalltalkCompiler 6 | + (NSString*) languageName 7 | { 8 | return @"Smalltalk"; 9 | } 10 | + (NSString*) fileExtension 11 | { 12 | return @"st"; 13 | } 14 | + (Class) parserClass 15 | { 16 | return [SmalltalkParser class]; 17 | } 18 | @end 19 | -------------------------------------------------------------------------------- /Smalltalk/SmalltalkParser.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class LKAST; 4 | @protocol LKParser; 5 | 6 | /** 7 | * Smalltalk parser class. This class implements a tokeniser and calls a 8 | * parser created using the Lemon parser generator. 9 | */ 10 | @interface SmalltalkParser : NSObject { 11 | LKAST *ast; 12 | } 13 | /** 14 | * Used by the Lemon implementation to feed the generated AST back so the 15 | * Parser can return it. 16 | */ 17 | - (void) setAST:(LKAST*)ast; 18 | @end 19 | -------------------------------------------------------------------------------- /Smalltalk/Support/BlockClosure.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | extern NSString *LKSmalltalkBlockNonLocalReturnException; 4 | 5 | @interface _NSBlock : NSObject 6 | - (id)value; 7 | @end 8 | 9 | @implementation _NSBlock (ExceptionHandling) 10 | - (id) onException: (NSString*) exceptionName do: (id(^)(id)) handler 11 | { 12 | @try 13 | { 14 | return [self value]; 15 | } 16 | @catch (NSException *localException) 17 | { 18 | // If this is an exception that the interpreter is using to fudge a 19 | // non-local return, chuck it out to the interpreter. 20 | if ([[localException name] isEqualToString: LKSmalltalkBlockNonLocalReturnException]) 21 | { 22 | [localException raise]; 23 | } 24 | if ((exceptionName == nil) || [[localException name] isEqualToString: exceptionName]) 25 | { 26 | return handler(localException); 27 | } 28 | else 29 | { 30 | [localException raise]; 31 | } 32 | } 33 | // Not reached 34 | return nil; 35 | } 36 | @end 37 | -------------------------------------------------------------------------------- /Smalltalk/Support/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | # We reset PROJECT_DIR provided by etoile.make to match the subproject since 4 | # etoile.make doesn't detect and handle such embedded project 5 | PROJECT_DIR = $(CURDIR) 6 | # We redefine the project name since the target name doesn't match the name 7 | # of the project directory (Support) 8 | PROJECT_NAME = SmalltalkSupport 9 | 10 | FRAMEWORK_NAME = SmalltalkSupport 11 | 12 | LIBRARIES_DEPEND_UPON += -lgmp -lLanguageKitRuntime $(FND_LIBS) $(OBJC_LIBS) $(SYSTEM_LIBS) 13 | 14 | ${FRAMEWORK_NAME}_CPPFLAGS += -D_POSIX_C_SOURCE=2 -I../../LanguageKit/Runtime 15 | ${FRAMEWORK_NAME}_OBJCFLAGS += -std=c99 -fexceptions 16 | ${FRAMEWORK_NAME}_CFLAGS += -std=c99 -fexceptions 17 | 18 | # 19 | # Class files 20 | # 21 | ${FRAMEWORK_NAME}_OBJC_FILES = \ 22 | BlockClosure.m\ 23 | NSArray+map.m\ 24 | NSObject+log.m\ 25 | NSObject+yourself.m\ 26 | NSString+casting.m\ 27 | NSString+comma.m\ 28 | NSValue+structs.m 29 | 30 | -include GNUmakefile.preamble 31 | include $(GNUSTEP_MAKEFILES)/framework.make 32 | -include ../../../etoile.make 33 | -include GNUmakefile.postamble 34 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSArray+map.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSArray (map) 4 | - (NSArray*) map:(id)aClosure; 5 | - (void) foreach:(id)aClosure; 6 | - (NSArray*) select:(id)aClosure; 7 | - (id) detect:(id)aClosure; 8 | - (id) fold:(id)aClosure; 9 | @end 10 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSArray+map.m: -------------------------------------------------------------------------------- 1 | #import "NSArray+map.h" 2 | #import "BlockClosure.h" 3 | #import 4 | 5 | @implementation NSArray (map) 6 | - (NSArray*) map:(id)aClosure 7 | { 8 | id new[[self count]]; 9 | int i = 0; 10 | FOREACHI(self, obj) 11 | { 12 | new[i] = [aClosure value:obj]; 13 | i++; 14 | } 15 | return [NSArray arrayWithObjects:new count:i]; 16 | } 17 | - (void) foreach:(id)aClosure 18 | { 19 | FOREACHI(self, obj) 20 | { 21 | [aClosure value:obj]; 22 | } 23 | } 24 | - (void) do:(id)aClosure 25 | { 26 | FOREACHI(self, obj) 27 | { 28 | [aClosure value:obj]; 29 | } 30 | } 31 | - (NSArray*) select:(id)aClosure 32 | { 33 | id new[[self count]]; 34 | int i = 0; 35 | FOREACHI(self, obj) 36 | { 37 | if ([[aClosure value:obj] boolValue]) 38 | { 39 | new[i++] = obj; 40 | } 41 | } 42 | return [NSArray arrayWithObjects:new count:i]; 43 | } 44 | - (id) detect:(id)aClosure 45 | { 46 | id new[[self count]]; 47 | int i = 0; 48 | FOREACHI(self, obj) 49 | { 50 | if ([[aClosure value:obj] boolValue]) 51 | { 52 | return obj; 53 | } 54 | } 55 | return nil; 56 | } 57 | - (id) inject:(id)aValue into:aClosure 58 | { 59 | id collect = aValue; 60 | FOREACHI(self, obj) 61 | { 62 | collect = [aClosure value:obj value:collect]; 63 | } 64 | return collect; 65 | } 66 | - (id) fold:(id)aClosure 67 | { 68 | return [self inject:nil into:aClosure]; 69 | } 70 | @end 71 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSObject+log.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation NSObject (log) 4 | - (void) log 5 | { 6 | NSLog(@"%@", [self description]); 7 | } 8 | - (void) printOn:(NSFileHandle*)handle 9 | { 10 | [handle writeData:[[self description] dataUsingEncoding:NSUTF8StringEncoding]]; 11 | } 12 | - (void) ifNotNil: (id(^)(void))aBlock 13 | { 14 | aBlock(); 15 | } 16 | @end 17 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSObject+yourself.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation NSObject (Yourself) 4 | - (id) yourself 5 | { 6 | return self; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSString+casting.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation NSString (Casting) 4 | - (unsigned int) unsignedIntValue 5 | { 6 | return (unsigned int)[self intValue]; 7 | } 8 | - (SEL) selValue 9 | { 10 | return NSSelectorFromString(self); 11 | } 12 | @end 13 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSString+comma.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation NSString (Comma) 4 | - (NSString *)comma: (NSString *)aString 5 | { 6 | return [self stringByAppendingString: aString]; 7 | } 8 | @end 9 | 10 | @implementation NSArray (Comma) 11 | - (NSArray *)comma: (NSArray *)anArray 12 | { 13 | return [self arrayByAddingObjectsFromArray: anArray]; 14 | } 15 | @end 16 | 17 | 18 | -------------------------------------------------------------------------------- /Smalltalk/Support/NSValue+structs.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation NSValue (structures) 4 | + (id) rangeWithLocation:(int)loc length:(int)len 5 | { 6 | return [NSValue valueWithRange:NSMakeRange(loc, len)]; 7 | } 8 | 9 | + (id) pointWithX:(float)x Y:(float)y 10 | { 11 | return [NSValue valueWithPoint:NSMakePoint(x, y)]; 12 | } 13 | 14 | + (id) rectWithX:(float)x Y:(float)y width:(float)width height:(float)height 15 | { 16 | return [NSValue valueWithRect:NSMakeRect(x, y, width, height)]; 17 | } 18 | 19 | + (id) sizeWithWidth:(float)width height:(float)height 20 | { 21 | return [NSValue valueWithSize:NSMakeSize(width, height)]; 22 | } 23 | 24 | - (unsigned int) location 25 | { 26 | return [self rangeValue].location; 27 | } 28 | 29 | - (unsigned int) length 30 | { 31 | return [self rangeValue].length; 32 | } 33 | 34 | - (float) x 35 | { 36 | return [self pointValue].x; 37 | } 38 | 39 | - (float) y 40 | { 41 | return [self pointValue].y; 42 | } 43 | 44 | - (NSValue *) origin 45 | { 46 | return [NSValue valueWithPoint: [self rectValue].origin]; 47 | } 48 | 49 | - (NSValue *) size 50 | { 51 | return [NSValue valueWithSize: [self rectValue].size]; 52 | } 53 | 54 | - (float) width 55 | { 56 | return [self sizeValue].width; 57 | } 58 | 59 | - (float) height 60 | { 61 | return [self sizeValue].height; 62 | } 63 | @end 64 | -------------------------------------------------------------------------------- /Smalltalk/Tests/InFutureTestBoxing/expected.txt: -------------------------------------------------------------------------------- 1 | This needs to compile. 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/InFutureTestBoxing/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: ICantDecide [ 3 | iCantDecide: arr [ 4 | arr size 5 | ] 6 | ] 7 | 8 | NSObject subclass: SmalltalkTool [ 9 | run [ 10 | ETTranscript show: 'This needs to compile.'; cr. 11 | ] 12 | ] 13 | -------------------------------------------------------------------------------- /Smalltalk/Tests/README: -------------------------------------------------------------------------------- 1 | 2 | Simple Smalltalk tests. 3 | 4 | Every directory starting with "Test" is considered a test. The file 5 | test.st is run with edlc. A tests succeeds when the output equals the 6 | contents of expected.txt in that directory. 7 | 8 | Run single tests with: 9 | sh runtest.sh TestName 10 | 11 | Run all tests with: 12 | sh runall.sh 13 | 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/Template/expected.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/etoile/Languages/068ed397496a4e445ff9af7b56e2c60a0126d783/Smalltalk/Tests/Template/expected.txt -------------------------------------------------------------------------------- /Smalltalk/Tests/Template/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestArrayLiterals/expected.txt: -------------------------------------------------------------------------------- 1 | (1, 2, 3) 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestArrayLiterals/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | ETTranscript show: {1. 2. 3}; cr. 5 | ] 6 | ] 7 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestBlockAssignment/expected.txt: -------------------------------------------------------------------------------- 1 | block called with the secret string in the withBlock: method 2 | block called with the first string 3 | block called with the second string 4 | done 5 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestBlockAssignment/test.st: -------------------------------------------------------------------------------- 1 | 2 | "This class stores a block." 3 | NSObject subclass: FilteredStringPrinter [ 4 | | myBlock | 5 | 6 | withBlock: aBlock [ 7 | "This is a setter, not an initialiser." 8 | myBlock := aBlock. 9 | myBlock value: 'the secret string in the withBlock: method'. 10 | ^self. 11 | ] 12 | 13 | doSomethingWith: str [ 14 | "This method will print str when the block evaluates to true." 15 | myBlock value: str. 16 | ] 17 | ] 18 | 19 | 20 | NSObject subclass: SmalltalkTool [ 21 | run [ 22 | | p | 23 | 24 | p := FilteredStringPrinter new withBlock: [ :x | 25 | ETTranscript show: 'block called with '; show: x; cr. 26 | ]. 27 | 28 | 29 | p doSomethingWith: 'the first string'; 30 | doSomethingWith: 'the second string'. 31 | 32 | ETTranscript show: 'done'; cr. 33 | ] 34 | ] 35 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestBlockReturn/expected.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 1 5 | 2 6 | 4 7 | 3 8 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestBlockReturn/test.st: -------------------------------------------------------------------------------- 1 | " 2 | This is a pretty hardcore test for closures I guess. 3 | The createCounter method returns a closure when it's 4 | called. This is done two times here. Each of the two 5 | closures should have its own enclosed count variable. 6 | When the returned blocks are evaluated multiple times, 7 | they are supposed to return increasing numbers. 8 | " 9 | NSObject subclass: SmalltalkTool [ 10 | createCounter [ 11 | | count | 12 | count := 0. 13 | ^ [ count := count + 1 ] 14 | ] 15 | 16 | log: item [ 17 | ETTranscript show: item. 18 | ETTranscript cr. 19 | ] 20 | 21 | run [ 22 | | a b | 23 | a := self createCounter. 24 | b := self createCounter. 25 | self log: a value. 26 | self log: a value. 27 | self log: a value. 28 | self log: b value. 29 | self log: b value. 30 | self log: a value. 31 | self log: b value. 32 | ] 33 | ] 34 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestBlockReturningABlock/expected.txt: -------------------------------------------------------------------------------- 1 | Outer block called. (1) 2 | Outer block called. (2) 3 | Inner block called. 4 | Inner block called. 5 | Outer block called. (3) 6 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestBlockReturningABlock/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | a count | 5 | 6 | count := 0. 7 | a := [ 8 | count := count + 1. 9 | ETTranscript show: 'Outer block called. ('; show: count; 10 | show: ')'; cr. 11 | [ 12 | ETTranscript show: 'Inner block called.'; cr. 13 | ] copy. 14 | ] copy. 15 | 16 | "Call outer" 17 | a value. 18 | "Call outer, then inner two times" 19 | a value value; value. 20 | "Call outer" 21 | a value. 22 | ] 23 | ] 24 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestCascadedMessages/expected.txt: -------------------------------------------------------------------------------- 1 | A simple test? 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestCascadedMessages/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | ETTranscript show: 'A simple test?'; cr. 5 | ] 6 | ] 7 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassMethods1/expected.txt: -------------------------------------------------------------------------------- 1 | simple class method invocation 2 | simple class method invocation 2 3 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassMethods1/test.st: -------------------------------------------------------------------------------- 1 | 2 | 3 | NSObject subclass: SmalltalkTool [ 4 | +show: string [ 5 | ETTranscript show: string. 6 | ETTranscript cr. 7 | ] 8 | 9 | run [ 10 | SmalltalkTool show: 'simple class method invocation'. 11 | self class show: 'simple class method invocation 2'. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassMethods2/expected.txt: -------------------------------------------------------------------------------- 1 | class method invocation 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassMethods2/test.st: -------------------------------------------------------------------------------- 1 | 2 | ETTranscript extend [ 3 | +puts: string [ 4 | self show: string. 5 | self cr. 6 | ] 7 | ] 8 | 9 | NSObject subclass: SmalltalkTool [ 10 | run [ 11 | ETTranscript puts: 'class method invocation'. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassMethods3/expected.txt: -------------------------------------------------------------------------------- 1 | from subclass: class method invocation 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassMethods3/test.st: -------------------------------------------------------------------------------- 1 | 2 | ETTranscript subclass: MyTranscript [ 3 | +show: string [ 4 | super show: 'from subclass: '. 5 | super show: string. 6 | ] 7 | ] 8 | 9 | NSObject subclass: SmalltalkTool [ 10 | run [ 11 | MyTranscript show: 'class method invocation'. 12 | MyTranscript cr. 13 | ] 14 | ] 15 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassVariables/expected.txt: -------------------------------------------------------------------------------- 1 | Class initialisation 2 | Object initialisation (a) 3 | Object initialisation (aa) 4 | Object initialisation (aaa) 5 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassVariables/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: Thing [ 3 | | +instances | 4 | 5 | +initialize [ 6 | ETTranscript show: 'Class initialisation'; cr. 7 | instances := NSMutableString new. 8 | ] 9 | 10 | init [ 11 | instances appendString: 'a'. 12 | ETTranscript show: 'Object initialisation ('; 13 | show: instances ; show: ')'; cr. 14 | ^ self. 15 | ] 16 | 17 | ] 18 | 19 | NSObject subclass: SmalltalkTool [ 20 | run [ 21 | | a b c | 22 | a := Thing new. 23 | b := Thing new. 24 | c := Thing new. 25 | ] 26 | ] 27 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassVariables2/expected.txt: -------------------------------------------------------------------------------- 1 | Class initialisation 2 | Object initialisation (42) 3 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestClassVariables2/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: Thing [ 3 | | +intClassVariable | 4 | 5 | +initialize [ 6 | ETTranscript show: 'Class initialisation'; cr. 7 | intClassVariable := 42. 8 | ] 9 | 10 | init [ 11 | ETTranscript show: 'Object initialisation ('; 12 | show: intClassVariable ; show: ')'; cr. 13 | ^ self. 14 | ] 15 | 16 | ] 17 | 18 | NSObject subclass: SmalltalkTool [ 19 | run [ 20 | | a | 21 | a := Thing new. 22 | ] 23 | ] 24 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestComplexBoxing/expected.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/etoile/Languages/068ed397496a4e445ff9af7b56e2c60a0126d783/Smalltalk/Tests/TestComplexBoxing/expected.txt -------------------------------------------------------------------------------- /Smalltalk/Tests/TestComplexBoxing/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | NSAffineTransform transform setTransformStruct: (NSAffineTransform transform transformStruct) 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestCountingWhileTrue/expected.txt: -------------------------------------------------------------------------------- 1 | xxxxx 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestCountingWhileTrue/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | curr max | 5 | max := 5. 6 | curr := 0. 7 | [ curr < max ] whileTrue: [ 8 | ETTranscript show: 'x'. 9 | curr := curr + 1. 10 | ]. 11 | ETTranscript cr. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestDealloc/expected.txt: -------------------------------------------------------------------------------- 1 | Sub destroyed 2 | Super destroyed 3 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestDealloc/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: Super [ 2 | dealloc [ ETTranscript show: 'Super destroyed' ; cr ] 3 | ] 4 | Super subclass: Sub [ 5 | dealloc [ ETTranscript show: 'Sub destroyed' ; cr ] 6 | ] 7 | NSObject subclass: SmalltalkTool 8 | [ 9 | run [ Sub new ] 10 | ] 11 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestDeeplyNestedBlocks/expected.txt: -------------------------------------------------------------------------------- 1 | two tigers 2 | two ducks 3 | three tigers 4 | three ducks 5 | four tigers 6 | four ducks 7 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestDeeplyNestedBlocks/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | numbers animals space | 5 | numbers := {'two'. 'three'. 'four'}. 6 | animals := {'tigers'. 'ducks'}. 7 | space := ' '. 8 | numbers do: [ :number | 9 | animals do: [ :animal | 10 | ETTranscript show: number. 11 | ETTranscript show: space. 12 | ETTranscript show: animal. 13 | ETTranscript cr. 14 | ]. 15 | ]. 16 | ] 17 | ] 18 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestFloatBoxing/expected.txt: -------------------------------------------------------------------------------- 1 | 3.14159 2 | 3.141590 3 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestFloatBoxing/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | | float | 4 | float := NSNumber numberWithFloat: '3.14159'. 5 | 6 | ETTranscript 7 | show: float; cr; 8 | show: float floatValue; cr. 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestInstanceVariables/expected.txt: -------------------------------------------------------------------------------- 1 | abcde 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestInstanceVariables/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: A[ 3 | | a b c | 4 | init [ 5 | a := 'a'. 6 | b := 'b'. 7 | c := 'c'. 8 | ^self. 9 | ] 10 | ] 11 | A subclass: B [ 12 | | d e | 13 | init [ 14 | super init. 15 | d := 'd'. 16 | e := 'e'. 17 | ^self. 18 | ] 19 | log [ 20 | ETTranscript show: a; 21 | show: b; 22 | show: c; 23 | show: d; 24 | show: e; cr. 25 | ] 26 | ] 27 | NSObject subclass: SmalltalkTool [ 28 | run [ 29 | B new log. 30 | ] 31 | ] 32 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIntArithmetic/expected.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 18446744073709551617 3 | 18446744073709551617 4 | 36893488147419103232 5 | 6 6 | 36893488147419103232 7 | 36893488147419103232 8 | 340282366920938463463374607431768211456 9 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIntArithmetic/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | ETTranscript show: 4 | (1 + 3); cr; show: 5 | (1 + 18446744073709551616); cr; show: 6 | (18446744073709551616 + 1); cr; show: 7 | (18446744073709551616 + 18446744073709551616); cr; show: 8 | 9 | (2 * 3); cr; show: 10 | (2 * 18446744073709551616); cr; show: 11 | (18446744073709551616 * 2); cr; show: 12 | (18446744073709551616 * 18446744073709551616); cr. 13 | ] 14 | ] 15 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIntegerAddition/expected.txt: -------------------------------------------------------------------------------- 1 | Integer addition: 2 | 3 3 | 5 4 | 5 5 | 10 6 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIntegerAddition/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | a b | 5 | a := 4. 6 | b := 6. 7 | ETTranscript show: 'Integer addition:'; cr; 8 | show: (1 + 2); cr; 9 | show: (a + 1); cr; 10 | show: (1 + a); cr; 11 | show: (a + b); cr. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIntegerUpTo/expected.txt: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 2 4 | 3 5 | 4 6 | 5 7 | 6 8 | 7 9 | 8 10 | 9 11 | 10 12 | 1000000000 13 | 1000000001 14 | 1000000002 15 | 1000000003 16 | 1000000004 17 | 1000000005 18 | 1000000006 19 | 1000000007 20 | 1000000008 21 | 1000000009 22 | 1000000010 23 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIntegerUpTo/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | print arr | 5 | print := [ :x | ETTranscript show: x; cr. ]. 6 | arr := { 'a'. 'b'. 'c'. 'd' }. 7 | 0 to: 10 do: print. 8 | 1000000000 to: 1000000010 do: print. 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIsAlphabetic/expected.txt: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestIsAlphabetic/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ 3 | ('a' characterAtIndex: 0) isAlphabetic ifTrue: 4 | [ETTranscript show: 'true'; cr] 5 | ifFalse: [ETTranscript show: 'false'; cr]. 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestJustAnInteger/expected.txt: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestJustAnInteger/test.st: -------------------------------------------------------------------------------- 1 | 2 | 3 | NSObject subclass: SmalltalkTool [ 4 | run [ 5 | "Crashes on Ubuntu 8.10 -Günther" 6 | ETTranscript show: 1; cr. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestKVC/expected.txt: -------------------------------------------------------------------------------- 1 | (null) 2 | something 3 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestKVC/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: TestObject 2 | [ 3 | whatever [ ^ nil. ] 4 | whichever [ ^ 'something'. ] 5 | ] 6 | NSObject subclass: SmalltalkTool 7 | [ 8 | run 9 | [ 10 | ETTranscript show: (TestObject new valueForKey: 'whatever') ; cr; 11 | show: (TestObject new valueForKey: 'whichever') ; cr. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestMutRecursiveClassDefs/expected.txt: -------------------------------------------------------------------------------- 1 | --- 2 | 0: a 3 | 1: b 4 | 2: c 5 | 3: d 6 | 4: e 7 | --- 8 | 0: c 9 | 1: d 10 | 2: e 11 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestMutRecursiveClassDefs/test.st: -------------------------------------------------------------------------------- 1 | << types = '{ count = I8@0:4; }' >> 2 | " 3 | Tests mutually recursive class dependencies. (The List class needs to 4 | know the SuffixList class to create suffices, but the suffix class is 5 | derived from the list class.) 6 | 7 | The code is modeled after NSArray and NSString-like class clusters for 8 | extra realism. 9 | " 10 | NSObject subclass: List [ 11 | suffixOfSize: n [ 12 | ^ SuffixList alloc initWithSource: self start: (self theSize - n) 13 | ] 14 | print [ 15 | ETTranscript show: '---'; cr. 16 | 0 to: (self theSize - 1) do: [ :x | 17 | ETTranscript show: x; show: ': '; show: (self at: x); cr. 18 | ] 19 | ] 20 | ] 21 | 22 | List subclass: SuffixList [ 23 | | fSrc fStart | 24 | initWithSource: src start: start [ 25 | fSrc := src. 26 | fStart := start 27 | ] 28 | at: i [ ^ fSrc at: fStart + i ] 29 | theSize [ ^ fSrc theSize - fStart ] 30 | ] 31 | 32 | List subclass: ActualList [ 33 | | fArray | 34 | initWithArray: arr [ fArray := arr ] 35 | at: i [ ^ fArray objectAtIndex: i ] 36 | theSize [ ^ fArray count ] 37 | ] 38 | 39 | NSObject subclass: SmalltalkTool [ 40 | run [ 41 | | l | 42 | l := ActualList alloc initWithArray: { 'a'. 'b'. 'c'. 'd'. 'e' }. 43 | l print. 44 | (l suffixOfSize: 3) print. 45 | ] 46 | ] 47 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSPointBoxing/expected.txt: -------------------------------------------------------------------------------- 1 | Boxing: 2 | {x = 1.100000; y = 10.200000} 3 | Unboxing: 4 | 1 5 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSPointBoxing/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | stringForPoint: point 3 | [ 4 | ^ '{x = ', (point x stringValue), '; y = ', (point y stringValue), '}'. 5 | ] 6 | 7 | run [ | point | 8 | point := NSValue pointWithX: '1.1' Y: '10.2'. 9 | point log. 10 | point pointValue log. 11 | ETTranscript 12 | show: 'Boxing:'; cr; 13 | show: (self stringForPoint: (point pointValue)); cr; 14 | show: 'Unboxing:'; cr; 15 | show: ((NSValue valueWithPoint: point) isEqualToValue: point); cr. 16 | ] 17 | ] 18 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSRangeBoxing/expected.txt: -------------------------------------------------------------------------------- 1 | Create range: 2 | {location=0, length=9} 3 | Substring 4 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSRangeBoxing/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ | range | 3 | range := (NSValue rangeWithLocation:0 length:9). 4 | ETTranscript 5 | show:'Create range: '; cr; 6 | show: range; cr; 7 | show: ('Substring of longer string' substringWithRange:range); cr. 8 | ] 9 | ] 10 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSRectBoxing/expected.txt: -------------------------------------------------------------------------------- 1 | Boxing: 2 | {x = 1.2; y = 2.7; width = 3.032; height = -5e+09} 3 | Unboxing: 4 | 1 5 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSRectBoxing/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | run [ | rect | 3 | rect := NSValue rectWithX: '1.2' Y: '2.7' width: '3.032' height: '-5000000000.11'. 4 | 5 | ETTranscript 6 | show: 'Boxing:'; cr; 7 | show: rect rectValue; cr; 8 | show: 'Unboxing:'; cr; 9 | show: ((NSValue valueWithRect: rect) isEqualToValue: rect); cr. 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSSizeBoxing/expected.txt: -------------------------------------------------------------------------------- 1 | Boxing: 2 | {width = 13.100000; height = 50.500000} 3 | Unboxing: 4 | 1 5 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNSSizeBoxing/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool [ 2 | stringForSize: size 3 | [ 4 | ^ '{width = ', (size width stringValue), '; height = ', (size height stringValue), '}'. 5 | ] 6 | 7 | run [ | size | 8 | size := NSValue sizeWithWidth: '13.1' height: '50.5'. 9 | ETTranscript 10 | show: 'Boxing:'; cr; 11 | show: (self stringForSize: (size sizeValue)); cr; 12 | show: 'Unboxing:'; cr; 13 | show: ((NSValue valueWithSize: size) isEqualToValue: size); cr. 14 | ] 15 | ] 16 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNestedBlocks/expected.txt: -------------------------------------------------------------------------------- 1 | two tigers 2 | two ducks 3 | three tigers 4 | three ducks 5 | four tigers 6 | four ducks 7 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNestedBlocks/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | numbers animals | 5 | numbers := {'two'. 'three'. 'four'}. 6 | animals := {'tigers'. 'ducks'}. 7 | numbers do: [ :number | 8 | animals do: [ :animal | 9 | ETTranscript show: number. 10 | ETTranscript show: ' '. 11 | ETTranscript show: animal. 12 | ETTranscript cr. 13 | ] 14 | ]. 15 | ] 16 | ] 17 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNonLocalReturn/expected.txt: -------------------------------------------------------------------------------- 1 | test succeeded 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNonLocalReturn/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | 4 | ignoresReturn: aBlock 5 | [ 6 | aBlock value. 7 | ^'test failed'. 8 | ] 9 | 10 | returnsObject 11 | [ 12 | "self ignoresReturn:[ ^'test succeeded' ]." 13 | 1 ifTrue: [ ^'test succeeded'] . 14 | ^'test failed' 15 | ] 16 | 17 | run [ 18 | ETTranscript show: self returnsObject; cr. 19 | 20 | ] 21 | ] 22 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNonLocalReturn2/expected.txt: -------------------------------------------------------------------------------- 1 | test succeeded 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestNonLocalReturn2/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | 4 | returnsObject 5 | [ 6 | true ifTrue: [ ^'test succeeded']. 7 | ^'test failed' 8 | ] 9 | 10 | run [ 11 | ETTranscript show: self returnsObject; cr. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestOperatorDefinition/expected.txt: -------------------------------------------------------------------------------- 1 | Urinstinkt 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestOperatorDefinition/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSString extend [ 3 | plus: anotherString [ 4 | ^self stringByAppendingString: anotherString. 5 | ] 6 | ] 7 | 8 | NSObject subclass: SmalltalkTool [ 9 | run [ 10 | ETTranscript show: 'Urin' + 'stinkt'. 11 | ETTranscript cr. 12 | ] 13 | ] 14 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestPolymorphicSelectors/expected.txt: -------------------------------------------------------------------------------- 1 | 42 2 | 12345 3 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestPolymorphicSelectors/test.st: -------------------------------------------------------------------------------- 1 | " -[URLProtectionSpace port] returns an int, -[NSURL port] return an object " 2 | 3 | "<< types = '{ port = i8@0:4; }' >>" 4 | "<< types = '{ port = @8@0:4; }' >>" 5 | 6 | NSObject subclass: SmalltalkTool [ 7 | run [ 8 | | urlProtectionSpace url | 9 | urlProtectionSpace := NSURLProtectionSpace alloc initWithHost:'' port:42 protocol:'' realm:'' authenticationMethod:''. 10 | url := NSURL alloc initWithString: 'http://www.etoileos.com:12345'. 11 | 12 | ETTranscript show: urlProtectionSpace port; 13 | cr; 14 | show: url port; cr. 15 | ] 16 | ] 17 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestScopes/expected.txt: -------------------------------------------------------------------------------- 1 | null2 2 | null 3 | set in secondMethod 4 | set in secondMethod 5 | set in inner block 6 | set in inner block 7 | set in inner block 8 | set in inner block 9 | set in inner block 10 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestScopes/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | | +aClassVar anIvar | 4 | run [ 5 | | methodLocal | 6 | methodLocal := 'null'. 7 | aClassVar := 'null'. 8 | anIvar := 'null'. 9 | self secondMethod. 10 | ETTranscript show: methodLocal; cr. 11 | ETTranscript show: anIvar; cr. 12 | ETTranscript show: aClassVar; cr. 13 | [ 14 | | blockLocal | 15 | [ 16 | methodLocal := 'set in inner block'. 17 | blockLocal := 'set in inner block'. 18 | aClassVar := 'set in inner block'. 19 | anIvar := 'set in inner block'. 20 | ] value. 21 | ETTranscript show: methodLocal; cr. 22 | ETTranscript show: blockLocal; cr. 23 | ETTranscript show: aClassVar; cr. 24 | ETTranscript show: anIvar; cr. 25 | ] value. 26 | 27 | self thirdMethod: [ 28 | ETTranscript show: methodLocal; cr. 29 | ]. 30 | ] 31 | 32 | secondMethod [ 33 | | methodLocal | 34 | methodLocal := 'null2'. 35 | ETTranscript show: methodLocal; cr. 36 | anIvar := 'set in secondMethod'. 37 | aClassVar := 'set in secondMethod'. 38 | ] 39 | 40 | thirdMethod: block [ 41 | | methodLocal | 42 | methodLocal := 'should never see!'. 43 | block value. 44 | ] 45 | ] 46 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestSimpleSelect/expected.txt: -------------------------------------------------------------------------------- 1 | (testThis) 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestSimpleSelect/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | ETTranscript show: ({'testThis'. 'doThat'} select: [ :x | x hasPrefix: 'test' ]) ; cr. 5 | ] 6 | ] 7 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestTimesRepeat/expected.txt: -------------------------------------------------------------------------------- 1 | Santa: Ho! Ho! Ho! 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestTimesRepeat/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | | two | 4 | 5 | run [ 6 | " 2 becomes a BigInt when assigned to an ivar." 7 | two := 2. 8 | 9 | ETTranscript show: 'Santa:'. 10 | " Test BitInt" 11 | two timesRepeat: [ ETTranscript show: ' Ho!'. ]. 12 | " Test SmallInt" 13 | 1 timesRepeat: [ ETTranscript show: ' Ho!'. ]. 14 | " Test BigInt negative arithmetic results with timesRepeat: " 15 | ( two - 5) timesRepeat: [ ETTranscript show: ' Ho!'. ]. 16 | " Test SmallInt negative arithmetic results with timesRepeat: " 17 | ( 2 - 5) timesRepeat: [ ETTranscript show: ' Ho!'. ]. 18 | ETTranscript cr. 19 | ] 20 | ] 21 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestTranscript/expected.txt: -------------------------------------------------------------------------------- 1 | Test1 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestTranscript/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | ETTranscript show: 'Test'. 5 | ETTranscript show: 1. 6 | ETTranscript cr. 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestYourself/expected.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | -------------------------------------------------------------------------------- /Smalltalk/Tests/TestYourself/test.st: -------------------------------------------------------------------------------- 1 | 2 | NSObject subclass: SmalltalkTool [ 3 | run [ 4 | | anArray | 5 | anArray := NSMutableArray new 6 | addObject: 'c'; 7 | addObject: 'a'; 8 | addObject: 'b'; 9 | sortUsingSelector: 'compare:'; 10 | yourself. " so the array is the value of this message cascade expression" 11 | 12 | anArray foreach: [ :x | ETTranscript show: x; cr ]. 13 | ] 14 | ] 15 | -------------------------------------------------------------------------------- /Smalltalk/Tests/XFAILPrototypes/expected.txt: -------------------------------------------------------------------------------- 1 | A string 2 | -------------------------------------------------------------------------------- /Smalltalk/Tests/XFAILPrototypes/test.st: -------------------------------------------------------------------------------- 1 | NSObject subclass: SmalltalkTool 2 | [ 3 | run 4 | [ 5 | | a | 6 | a := NSObject new. 7 | a becomePrototype. 8 | a setValue:[ :object :aValue | ETTranscript show:aValue; cr ] 9 | forKey:'logValue:'. 10 | a logValue:'A string'. 11 | ] 12 | ] 13 | -------------------------------------------------------------------------------- /Smalltalk/Tests/XFAILRtainOnlyOnce/expected.txt: -------------------------------------------------------------------------------- 1 | I retain only once. 2 | Vroom, vroom! 3 | 4 | -------------------------------------------------------------------------------- /Smalltalk/Tests/XFAILRtainOnlyOnce/test.st: -------------------------------------------------------------------------------- 1 | 2 | " 3 | Problem: The log message in -retain appears very often, 4 | then a segfault occurs (try redirecting stdout to /dev/null 5 | for easier reproduction). 6 | " 7 | 8 | NSObject subclass: Car [ 9 | retain [ 10 | ETTranscript show: 'I retain only once.'; cr. 11 | super retain. 12 | ] 13 | 14 | drive [ 15 | ETTranscript show: 'Vroom, vroom!'; cr. 16 | ] 17 | ] 18 | 19 | 20 | NSObject subclass: SmalltalkTool [ 21 | run [ 22 | | car | 23 | car := Car new. 24 | car drive. 25 | ] 26 | ] 27 | -------------------------------------------------------------------------------- /Smalltalk/Tests/newtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | svn mkdir $1 4 | cp Template/test.st $1/test.st 5 | cp Template/expected.txt $1/expected.txt 6 | 7 | 8 | -------------------------------------------------------------------------------- /Smalltalk/Tests/runall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | QUIET=0 4 | set -- `getopt q "$@"` 5 | while [ $# -gt 0 ] 6 | do 7 | case "$1" in 8 | -q) QUIET=1; break;; 9 | --) shift; break;; 10 | *) break;; 11 | esac 12 | shift 13 | done 14 | 15 | PASSES=0 16 | FAILS=0 17 | # run the tests contained in the Test* directories 18 | for i in Test*; do 19 | if [ 1 -eq $QUIET ] ; then 20 | if (sh runtest.sh $i -i > /dev/null 2>&1) ; then 21 | PASSES=`expr $PASSES + 1` 22 | echo -n . 23 | else 24 | FAILS=`expr $FAILS + 1` 25 | echo -n '{FAIL (interpreter): '$i'}' 26 | fi 27 | else 28 | sh runtest.sh $i -i 29 | fi 30 | if [ 1 -eq $QUIET ] ; then 31 | if (sh runtest.sh $i > /dev/null 2>&1) ; then 32 | PASSES=`expr $PASSES + 1` 33 | echo -n . 34 | else 35 | FAILS=`expr $FAILS + 1` 36 | echo -n '{FAIL: '$i'}' 37 | fi 38 | else 39 | sh runtest.sh $i 40 | fi 41 | done 42 | if [ 1 -eq $QUIET ] ; then 43 | echo 44 | echo `expr $PASSES + $FAILS` tests run. $PASSES passed, $FAILS failed. 45 | fi 46 | rm -f */*.core 47 | exit $FAILS 48 | -------------------------------------------------------------------------------- /Smalltalk/Tests/runtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EXIT=0 4 | SCRIPT=$1 5 | shift 6 | cd ${SCRIPT} 7 | echo "------------------------------------------------------" 8 | echo "Test: ${SCRIPT} $@" 9 | if (edlc $@ -f test.st > results.txt 2>/dev/null) ; then 10 | if [ -f results.txt ]; then 11 | if cmp results.txt expected.txt > /dev/null; then 12 | echo -e "\033[0;32m${SCRIPT}: OK\033[m" 13 | else 14 | echo -e "\033[0;31m${SCRIPT}: FAIL\033[m" 15 | EXIT=1 16 | echo 'result | expected' 17 | sdiff results.txt expected.txt 18 | fi 19 | rm results.txt 20 | else 21 | EXIT=2 22 | echo -e "\033[0;31m${SCRIPT}: FAIL (gave no output)\033[m" 23 | fi 24 | else 25 | EXIT=3 26 | echo -e "\033[0;33m${SCRIPT}: FAIL (crash)\033[m" 27 | fi 28 | cd .. 29 | exit $EXIT 30 | --------------------------------------------------------------------------------