struct SumType { unsigned ActualTypeTag; union { // Each base type has an entry here, so e.g. int and float } Contents; };
structure Numeric : integer alpha, integer beta structure Textual : string alpha, string beta operate : Numeric n -> integer gamma = n.alpha + n.beta // addition operate : Textual t -> string gamma = n.alpha ; n.beta // string concatenation
type Anything : Numeric | Textual entrypoint : { Anything a = Numeric(40, 2) Anything b = Textual("Hello ", "World") print(operate(a)) print(operate(b)) }
type Geometry : Sphere | Box | Cylinder | PolygonMesh collide : Sphere s1, Sphere s2 -> boolean collision = false { ... } collide : Sphere s, Box b -> boolean collision = false { ... } collide : Cylinder c, Box b -> boolean collision = false { ... } // and so on
// // Some working thought-space for the raytracer project for R14 // type listnode<type T> : list<T> | nothing structure list<type T> : T value, listnode<T> next structure Point : real x, real y, real z // TODO - fix type aliases structure Vector : real x, real y, real z structure Ray : Point origin, Vector direction structure Sphere : Point center, real radius structure Plane : Point origin, Vector normal type Geometry : Sphere | Plane structure Color : real r, real g, real b structure Light : Point location, Color color, real intensity dot : Vector ref v1, Vector ref v2 -> v1.x * v2.x + v1.y * v2.y + v1.z * v2.z [native] dot : Vector ref v1, Point ref v2 -> v1.x * v2.x + v1.y * v2.y + v1.z * v2.z [native] dot : Point ref v1, Point ref v2 -> v1.x * v2.x + v1.y * v2.y + v1.z * v2.z [native] intersect : Plane ref p, Ray ref r -> real t = 100000.0 { // TODO - implement plane intersection code } intersect : Sphere ref s, Ray ref r -> real t = 100000.0 [native] { real b = dot(r.direction, r.origin) real c = dot(r.origin, r.origin) - 1.0 real disc = 4.0 * (b * b - c) if(disc > 0.0) { real distSqrt = sqrt(disc) real t0 = 0.0 if(b < 0.0) { t0 = (-2.0*b - distSqrt) / 2.0 } else { t0 = (-2.0*b + distSqrt) / 2.0 } real t1 = c / t0 if(t0 > t1) { real temp = t0 t0 = t1 t1 = temp } if(t1 > 0.0) { if(t0 < 0.0) { t = t1 } else { t = t0 } } } } intersect : nothing, Ray ref r -> 100000.0 structure Camera : Point location, Vector direction, real horizontalFOV, real verticalFOV structure Scene : list<Geometry> objects, list<Light> lights, Camera camera test : nothing, Ray ref r, Geometry ref closest -> 100000.0 test : list<Geometry> ref geometry, Ray ref r, Geometry ref closest -> real t = 100000.0 { real thist = intersect(geometry.value, r) if(thist < t) { t = thist closest = geometry.value } listnode<Geometry> nextnode = geometry.next real nextt = test(nextnode, r, closest) if(nextt < t) { t = nextt } } findclosesthit : Scene ref scene, Ray ref r, real ref t, Geometry ref closest { t = test(scene.objects, r, closest) } shade : Scene ref scene, Ray ref r, real t, Sphere ref obj -> Color c = 0.0, 0.0, 0.0 { real px = r.origin.x + r.direction.x * t real py = r.origin.y + r.direction.y * t real pz = r.origin.z + r.direction.z * t // Hack: assume our intersection point lies on a unit sphere, so the normal == point Vector normal = px, py, pz Vector lightdir = 3.0 - px, 3.0 - py, -8.0 - pz normalize(lightdir) real i = dot(normal, lightdir) if(i > 0.0) { c.r = i * 0.306 c.g = i * 0.584 c.b = i * 0.816 } } trace : Scene ref scene, Ray ref r -> integer c = 0 { Geometry closestobj = scene.objects.value real t = 100000.0 findclosesthit(scene, r, t, closestobj) if(t < 100000.0) { Color color = shade(scene, r, t, closestobj) c = rgb(color) } } structure Point2D : integer x, integer y structure Rect : integer left, integer top, integer right, integer bottom structure PaintInfo : integer hdc, boolean erase, Rect paintarea, boolean restore, boolean incupdate, integer reserved0, integer reserved1, integer reserved2, integer reserved3, integer reserved4, integer reserved5, integer reserved6, integer reserved7 structure WindowClass : integer Size, integer Style, (WindowProc : integer, integer, integer, integer -> integer), integer ClassExtra, integer WindowExtra, integer hInstance, integer hIcon, integer hCursor, integer hBackgroundBrush, string MenuName, string ClassName, integer hIconSmall structure MessageInfo : integer hwnd, integer message, integer wparam, integer lparam, integer time, Point2D point GetModuleHandle : integer null -> integer handle = 0 [external("Kernel32.dll", "GetModuleHandleW")] RegisterClassEx : WindowClass wc -> integer16 atom = 0 [external("User32.dll", "RegisterClassExW")] CreateWindowEx : integer exstyle, string classname, string windowname, integer style, integer x, integer y, integer width, integer height, integer hwndparent, integer hmenu, integer hinstance, integer param -> integer windowhandle = 0 [external("User32.dll", "CreateWindowExW")] ShowWindow : integer hwnd, integer cmdshow -> integer success = 0 [external("User32.dll", "ShowWindow")] GetMessage : MessageInfo ref msg, integer hwnd, integer filtermin, integer filtermax -> boolean success = false [external("User32.dll", "GetMessageW")] TranslateMessage : MessageInfo msg -> boolean success = false [external("User32.dll", "TranslateMessage")] DispatchMessage : MessageInfo msg -> integer unused = 0 [external("User32.dll", "DispatchMessageW")] BeginPaint : integer hwnd, PaintInfo ref paintinfo -> integer hdc = 0 [external("User32.dll", "BeginPaint")] EndPaint : integer hwnd, PaintInfo paintinfo -> integer success = 0 [external("User32.dll", "EndPaint")] PostQuitMessage : integer exitcode [external("User32.dll", "PostQuitMessage")] DefWindowProc : integer hwnd, integer msg, integer wparam, integer lparam -> integer ret = 0 [external("User32.dll", "DefWindowProcW")] DestroyWindow : integer handle -> integer ret = 0 [external("User32.dll", "DestroyWindow")] LoadCursor : integer hinstance, integer cursorid -> integer cursorhandle = 0 [external("User32.dll", "LoadCursorW")] MessageBox : integer hwnd, string message, string caption, integer style -> integer ret = 0 [external("User32.dll", "MessageBoxW")] global { buffer RenderedBitmap = 300 * 300 * 4 } normalize : Vector ref in [native] { real length = sqrt(in.x * in.x + in.y * in.y + in.z * in.z) in.x = in.x / length in.y = in.y / length in.z = in.z / length } rgb : Color ref c -> integer ret = 0 { ret += cast(integer, c.b * 255.0) ret += cast(integer, c.g * 255.0) * 256 ret += cast(integer, c.r * 255.0) * 65536 } timeGetTime : -> integer ms = 0 [external("WinMM.dll", "timeGetTime")] entrypoint : { Point zero = 0.0, 0.0, 0.0 Vector zero2 = 0.0, 0.0, 0.0 Sphere sphere = zero, 1.0 Color white = 1.0, 1.0, 1.0 Light light = zero, white, 1.0 list<Geometry> objects = sphere, nothing list<Light> lights = light, nothing Camera camera = Point(0.0, 0.0, -10.0), Vector(0.0, 0.0, 1.0), 1.0, 1.0 Scene scene = objects, lights, camera Ray ray = Point(0.0, 0.0, -10.0), zero2 integer startms = timeGetTime() integer yoffset = 0 integer y = 0 integer x = 0 real rayy = 0.0 while(y < 300) { rayy = cast(real, 150 - y) / 300.0 yoffset = (300 - y) * 300 x = 0 while(x < 300) { ray.direction.x = cast(real, 150 - x) / 300.0 ray.direction.y = rayy ray.direction.z = 1.0 normalize(ray.direction) integer c = trace(scene, ray) plotpixel(RenderedBitmap, (yoffset + x), c) ++x } ++y } integer endms = timeGetTime() print("Render complete, time in ms: " ; cast(string, endms - startms)) DisplayWindow() } AdjustWindowRect : Rect ref r, integer style, boolean menu -> boolean result = false [external("User32.dll", "AdjustWindowRect")] DisplayWindow : { integer IDC_ARROW = 32512 integer COLOR_WINDOWFRAME = 6 integer WS_OVERLAPPEDWINDOW = 13565952 integer CW_USEDEFAULT = -2147483648 integer SW_SHOW = 5 integer MB_ICONEXCLAMATION = 0x30 integer hInstance = GetModuleHandle(0) WindowClass wc = sizeof(wc), 0, MainWindowProcedure, 0, 0, hInstance, 0, LoadCursor(0, IDC_ARROW), COLOR_WINDOWFRAME, "", "RaytracerClass", 0 RegisterClassEx(wc) Rect adjusted = 0, 0, 300, 300 AdjustWindowRect(adjusted, WS_OVERLAPPEDWINDOW, false) integer hwnd = CreateWindowEx(0, "RaytracerClass", "Raytracer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, adjusted.right - adjusted.left, adjusted.bottom - adjusted.top, 0, 0, hInstance, 0) ShowWindow(hwnd, SW_SHOW) Point2D pt = 0, 0 MessageInfo msg = 0, 0, 0, 0, 0, pt while(GetMessage(msg, 0, 0, 0)) { TranslateMessage(msg) DispatchMessage(msg) } } structure BitmapInfoHeader : integer size, integer width, integer height, integer16 planes, integer16 bitcount, integer compression, integer sizeimage, integer xppm, integer yppm, integer used, integer important SetDIBitsToDevice : integer hdc, integer xdest, integer ydest, integer width, integer height, integer xsrc, integer ysrc, integer startscan, integer scanlines, buffer ref bits, BitmapInfoHeader ref bitmap, integer coloruse -> integer unused = 0 [external("Gdi32.dll", "SetDIBitsToDevice")] MainWindowProcedure : integer hwnd, integer message, integer wparam, integer lparam -> integer ret = 0 { integer WM_PAINT = 15 integer WM_DESTROY = 2 integer DIB_RGB_COLORS = 0 if(message == WM_PAINT) { Rect prect = 0, 0, 0, 0 PaintInfo ps = 0, false, prect, false, false, 0, 0, 0, 0, 0, 0, 0, 0 integer hdc = BeginPaint(hwnd, ps) BitmapInfoHeader bitmap = sizeof(bitmap), 300, 300, 1, 32, 0, 0, 0, 0, 0, 0 SetDIBitsToDevice(hdc, 0, 0, 300, 300, 0, 0, 0, 300, RenderedBitmap, bitmap, DIB_RGB_COLORS) EndPaint(hwnd, ps) } elseif(message == WM_DESTROY) { PostQuitMessage(0) } else { ret = DefWindowProc(hwnd, message, wparam, lparam) } }
// // GENERICLIST.EPOCH // // Simple implementation of a singly linked list holding arbitrary data // type listnode<type T> : list<T> | nothing structure list<type T> : T value, listnode<T> next prepend<type T> : list<T> ref thelist, T value { list<T> newlist = value, thelist thelist = newlist } append_recurse<type T> : list<T> ref thelist, nothing, T value { list<T> newlist = value, nothing thelist.next = newlist } append_recurse<type T> : list<T> ref thelist, list<T> ref tail, T value { append_recurse<T>(tail, tail.next, value) } append<type T> : list<T> ref thelist, T value { append_recurse<T>(thelist, thelist.next, value) } next<type T> : list<T> ref thelist -> listnode<T> tail = thelist.next next<type T> : nothing -> listnode<T> tail = nothing checkvalue<type T> : list<T> ref thelist, T expected { assert(thelist.value == expected) } checkvalue<type T> : nothing, T expected { print("Unexpected end of list") assert(false) } dumplist<type T> : list<T> ref thelist { listnode<T> nn = thelist.next dumplist(nn) } dumplist<type T> : nothing { } entrypoint : { list<integer> numbers = 1, nothing append<integer>(numbers, 2) append<integer>(numbers, 666) prepend<integer>(numbers, 0) dumplist<integer>(numbers) assert(numbers.value == 0) listnode<integer> node = next<integer>(numbers) checkvalue<integer>(node, 1) node = next<integer>(node) checkvalue<integer>(node, 2) node = next<integer>(node) checkvalue<integer>(node, 666) passtest() }
// // LISTOFINTEGERS.EPOCH // // Simple implementation of a singly linked list holding integers // type listnode : list | nothing structure list : integer value, listnode next prepend : list ref thelist, integer value { list newlist = value, thelist thelist = newlist } append : list ref thelist, integer value { append_recurse(thelist, thelist.next, value) } append_recurse : list ref thelist, nothing, integer value { list newlist = value, nothing thelist.next = newlist } append_recurse : list ref thelist, list ref tail, integer value { append_recurse(tail, tail.next, value) } next : list ref thelist -> listnode tail = thelist.next next : nothing -> listnode tail = nothing checkvalue : list ref thelist, integer expected { assert(thelist.value == expected) } checkvalue : nothing, integer expected { print("Unexpected end of list") assert(false) } dumplist : list ref thelist { listnode nn = thelist.next dumplist(nn) } dumplist : nothing { } entrypoint : { list numbers = 1, nothing append(numbers, 2) append(numbers, 3) prepend(numbers, 0) dumplist(numbers) assert(numbers.value == 0) listnode node = next(numbers) checkvalue(node, 1) node = next(node) checkvalue(node, 2) node = next(node) checkvalue(node, 3) print("Pass") }
structure testwrapper<type T> : T contents, string tag entrypoint : { testwrapper<integer> intwrap = 42, "number" testwrapper<string> strwrap = "test", "text" assert(intwrap.contents == 42) assert(strwrap.contents == "test") print("Pass") }
add<type T> : T a, T b -> T sum = a + b entrypoint : { integer foo = add<integer>(40, 2) integer bar = add<real>(3.0, 0.14) assert(foo == 42) assert(bar == 3.14) print("Pass") }