deleted web and dist

This commit is contained in:
Andreas Rumpf
2008-08-23 11:32:48 +02:00
parent 07d5a8085b
commit 972c510861
50 changed files with 4986 additions and 2289 deletions

View File

@@ -10,3 +10,4 @@ doc/*.html
*.zip
*.tar.gz
dist
dist

154
config/my_nimrod.cfg Normal file
View File

@@ -0,0 +1,154 @@
# Configuration file for the Nimrod Compiler.
# Generated by the koch.py script.
# (c) 2008 Andreas Rumpf
# Feel free to edit the default values as you need.
# You may set environment variables with
# @putenv "key" "val"
# Environment variables cannot be used in the options, however!
# Just call the compiler with several options:
cc = @if unix: gcc @else: vcc @end
lib="$nimrod/lib"
path="$lib/base"
path="$lib/base/gtk"
path="$lib/base/cairo"
path="$lib/base/x11"
path="$lib/windows"
path="$lib/posix"
path="$lib/ecmas"
path="$lib/extra"
@if release:
checks:off
stacktrace:off
debugger:off
line_dir:off
@end
# additional defines:
#define=""
# additional options always passed to the compiler:
force_build
line_dir=off
cfilecache=on
hint[LineTooLong]=off
hint[XDeclaredButNotUsed]=off
@if unix:
passl= "-ldl"
path = "$lib/base/gtk"
@end
@if icc:
passl = "-cxxlib"
passc = "-cxxlib"
@end
# Configuration for the LLVM GCC compiler:
@if windows:
llvm_gcc.path = r"$nimrod\dist\llvm-gcc4.2\bin"
@end
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
llvm_gcc.options.speed = "-O3 -ffast-math"
llvm_gcc.options.size = "-Os -ffast-math"
# Configuration for the Borland C++ Compiler:
@if windows:
bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"
@end
bcc.options.debug = ""
# turn off warnings about unreachable code and inline procs:
bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
bcc.options.speed = "-O2 -6"
bcc.options.size = "-O1 -6"
# Configuration for the Visual C/C++ compiler:
@if vcc:
@prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"
@prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"
@prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"
@end
@if windows:
vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"
@end
vcc.options.debug = "/RTC1 /ZI"
vcc.options.always = "/nologo"
vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
vcc.options.size = "/O1 /G7"
# Configuration for the Watcom C/C++ compiler:
@if windows:
wcc.path = r"C:\eigenes\compiler\watcom\binnt"
@end
wcc.options.debug = "-d2"
wcc.options.always = "-6 -zw -w-"
wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
# Configuration for the GNU C/C++ compiler:
@if windows:
gcc.path = r"C:\eigenes\compiler\mingw\bin"
@end
gcc.options.debug = "-g"
@if macosx:
gcc.options.always = "-w -fasm-blocks"
@else:
gcc.options.always = "-w"
@end
gcc.options.speed = "-O3 -ffast-math"
gcc.options.size = "-Os -ffast-math"
# Configuration for the Digital Mars C/C++ compiler:
@if windows:
dmc.path = r"C:\eigenes\compiler\d\dm\bin"
@end
dmc.options.debug = "-g"
dmc.options.always = "-Jm"
dmc.options.speed = "-ff -o -6"
dmc.options.size = "-ff -o -6"
# Configuration for the LCC compiler:
@if windows:
lcc.path = r"C:\eigenes\compiler\lcc\bin"
@end
lcc.options.debug = "-g5"
lcc.options.always = "-e1"
lcc.options.speed = "-O -p6"
lcc.options.size = "-O -p6"
# Configuration for the Tiny C Compiler:
@if windows:
tcc.path = r"C:\eigenes\compiler\tcc\bin"
@end
tcc.options.debug = "-b"
tcc.options.always = ""
tcc.options.speed = ""
tcc.options.size = ""
# Configuration for the Pelles C compiler:
@if windows:
pcc.path = r"C:\eigenes\compiler\pellesc\bin"
@end
pcc.options.debug = "-Zi"
pcc.options.always = "-Ze"
pcc.options.speed = "-Ox"
pcc.options.size = "-Os"
@if windows:
icc.path = r"c:\eignes\compiler\icc\bin"
@end
icc.options.debug = "-g"
icc.options.always = "-w"
icc.options.speed = "-O3 -ffast-math"
icc.options.size = "-Os -ffast-math"
@write "used default config file"
@if ecmascript:
@write "Target is ECMAScript! No unsafe features are allowed!"
@end

287
config/old_doctempl.cfg Normal file
View File

@@ -0,0 +1,287 @@
# This is the config file for the documentation generator.
# (c) 2008 Andreas Rumpf
# Feel free to edit the templates as you need.
doc.section = """
<div class="section" id="$sectionID">
<h1><a class="toc-backref" href="#$sectionTitleID">$sectionTitle</a></h1>
<dl class="item">
$content
</dl></div>
"""
doc.section.toc = """
<li>
<a class="reference" href="#$sectionID" id="$sectionTitleID">$sectionTitle</a>
<ul class="simple">
$content
</ul>
</li>
"""
doc.item = """
<dt id="$itemID"><pre>$header</pre></dt>
<dd>
$desc
</dd>
"""
doc.item.toc = """
<li><a class="reference" href="#$itemID">$name</a></li>
"""
doc.toc = """
<div class="navigation">
<p class="topic-title first">Navigation</p>
<ul class="simple">
$content
</ul>
</div>"""
doc.body_toc = """
$tableofcontents
<div class="content">
$moduledesc
$content
</div>
"""
doc.body_no_toc = """
$moduledesc
$content
"""
doc.file = """<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- This file is generated by Nimrod. -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>$title</title>
<style type="text/css">
span.DecNumber {color: blue}
span.BinNumber {color: blue}
span.HexNumber {color: blue}
span.OctNumber {color: blue}
span.FloatNumber {color: blue}
span.Identifier {color: black}
span.Keyword {font-weight: bold}
span.StringLit {color: blue}
span.LongStringLit {color: blue}
span.CharLit {color: blue}
span.EscapeSequence {color: black}
span.Operator {color: black}
span.Punctation {color: black}
span.Comment, span.LongComment {font-style:italic; color: green}
span.RegularExpression {color: pink}
span.TagStart {color: yellow}
span.TagEnd {color: yellow}
span.Key {color: blue}
span.Value {color: black}
span.RawData {color: blue}
span.Assembler {color: blue}
span.Preprocessor {color: yellow}
span.Directive {color: yellow}
span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
span.Other {color: black}
div.navigation {
float: left; width: 20em;
margin: 0; padding: 0; /*
border: 1px dashed gold; */
outline: 3px outset #99ff99; //gold;
background-color: #99ff99;
}
div.navigation ul {list-style-type: none;}
div.navigation ul li a, div.navigation ul li a:visited {
font-weight: bold;
color: #CC0000;
text-decoration: none;
}
div.navigation ul li a:hover {
font-weight: bold;
text-decoration: none;
outline: 2px outset gold;
background-color: gold; /* #779977;*/
}
div.content {
margin-left: 20em;
padding: 0 1em;
border: 1px dashed gold;
min-width: 16em;
}
dl.item dd, dl.item dd p {
margin-top:3px;
}
dl.item dd pre {
margin-left: 15pt;
border: 0px;
}
dl.item dt, dl.item dt pre {
margin: 20pt 0 0 0;
}
pre, span.tok {
background-color:#F9F9F9;
border:1px dotted #2F6FAB;
color:black;
}
/*
:Author: David Goodger
:Contact: goodger@python.org
:Date: Date: 2006-05-21 22:44:42 +0200 (Sun, 21 May 2006)
:Revision: Revision: 4564
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th { border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first { margin-top: 0 ! important }
.last, .with-subtitle { margin-bottom: 0 ! important }
.hidden { display: none }
a.toc-backref { text-decoration: none ; color: black }
blockquote.epigraph { margin: 2em 5em ; }
dl.docutils dd { margin-bottom: 0.5em }
div.abstract { margin: 2em 5em }
div.abstract p.topic-title { font-weight: bold ; text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ; border: medium outset ; padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title { font-weight: bold ; font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title { color: red ; font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication { margin: 2em 5em ; text-align: center ; font-style: italic }
div.dedication p.topic-title { font-weight: bold ; font-style: normal }
div.figure { margin-left: 2em ; margin-right: 2em }
div.footer, div.header { clear: both; font-size: smaller }
div.line-block { display: block ; margin-top: 1em ; margin-bottom: 1em }
div.line-block div.line-block { margin-top: 0 ; margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar { margin-left: 1em ; border: medium outset ;
padding: 1em ; background-color: #ffffee ; width: 40% ; float: right ;
clear: right }
div.sidebar p.rubric { font-family: sans-serif ; font-size: medium }
div.system-messages { margin: 5em }
div.system-messages h1 { color: red }
div.system-message { border: medium outset ; padding: 1em }
div.system-message p.system-message-title { color: red ; font-weight: bold }
div.topic { margin: 2em;}
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title { text-align: center }
h2.subtitle { text-align: center }
hr.docutils { width: 75% }
img.align-left { clear: left }
img.align-right { clear: right }
ol.simple, ul.simple { margin-bottom: 1em }
ol.arabic { list-style: decimal }
ol.loweralpha { list-style: lower-alpha }
ol.upperalpha { list-style: upper-alpha }
ol.lowerroman { list-style: lower-roman }
ol.upperroman { list-style: upper-roman }
p.attribution { text-align: right ; margin-left: 50% }
p.caption { font-style: italic }
p.credits { font-style: italic ; font-size: smaller }
p.label { white-space: nowrap }
p.rubric { font-weight:bold;font-size:larger;color:maroon;text-align:center}
p.sidebar-title {font-family: sans-serif ;font-weight: bold ;font-size: larger }
p.sidebar-subtitle {font-family: sans-serif ; font-weight: bold }
p.topic-title { font-weight: bold }
pre.address { margin-bottom: 0;margin-top:0;font-family:serif;font-size:100% }
pre.literal-block, pre.doctest-block {margin-left: 2em ;margin-right: 2em }
span.classifier {font-family: sans-serif;font-style: oblique }
span.classifier-delimiter {font-family: sans-serif;font-weight: bold }
span.interpreted {font-family: sans-serif }
span.option {white-space: nowrap }
span.pre {white-space: pre }
span.problematic {color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation { border-left: solid 1px gray; margin-left: 1px }
table.docinfo {margin: 2em 4em }
table.docutils {margin-top: 0.5em;margin-bottom: 0.5em }
table.footnote {border-left: solid 1px black;margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {padding-left: 0.5em;padding-right: 0.5em;
vertical-align: top}
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold;text-align: left;white-space: nowrap;padding-left: 0 }
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {font-size: 100% }
ul.auto-toc { list-style-type: none }
/*a.reference { color: #E00000; font-weight:bold;}
a.reference:hover {color: #E00000;background-color: #ffff00;display: margin;
font-weight:bold;}*/
</style>
<script type="text/javascript">
//<![CDATA[
function toggleElem(id) {
var e = document.getElementById(id);
e.style.display = e.style.display == 'none' ? 'block' : 'none';
}
var gOpen = 'none'
function toggleAll() {
gOpen = gOpen == 'none' ? 'block' : 'none';
var i = 1
while (1) {
var e = document.getElementById("m"+i)
if (!e) break;
e.style.display = gOpen
i++;
}
document.getElementById('toggleButton').value =
gOpen == 'none' ? 'Show Details' : 'Hide Details';
}
//]]>
</script>
</head>
<body>
<div class="document" id="documentId">
<h1 class="title">$title</h1>
$content
<small>Generated: $date $time UTC</small>
</div>
</body>
</html>
"""

165
config/old_nimrod.cfg Normal file
View File

@@ -0,0 +1,165 @@
# Configuration file for the Nimrod Compiler.
# Generated by the koch.py script.
# (c) 2008 Andreas Rumpf
# Feel free to edit the default values as you need.
# You may set environment variables with
# @putenv "key" "val"
# Environment variables cannot be used in the options, however!
# Just call the compiler with several options:
cc = @if unix: gcc @else: vcc @end
lib="$nimrod/lib"
path="$lib/base"
path="$lib/base/gtk"
path="$lib/base/cairo"
path="$lib/base/x11"
path="$lib/windows"
path="$lib/posix"
path="$lib/ecmas"
path="$lib/extra"
@if release:
checks:off
stacktrace:off
debugger:off
line_dir:off
@end
# additional defines:
#define=""
# additional options always passed to the compiler:
force_build
line_dir=off
cfilecache=on
hint[LineTooLong]=off
hint[XDeclaredButNotUsed]=off
@if unix:
passl= "-ldl"
path = "$lib/base/gtk"
@end
@if icc:
passl = "-cxxlib"
passc = "-cxxlib"
@end
# Configuration for the LLVM GCC compiler:
@if windows:
llvm_gcc.path = r"$nimrod\dist\llvm-gcc4.2\bin"
@end
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
llvm_gcc.options.speed = "-O3 -ffast-math"
llvm_gcc.options.size = "-Os -ffast-math"
# Configuration for the Borland C++ Compiler:
@if windows:
bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"
@end
bcc.options.debug = ""
# turn off warnings about unreachable code and inline procs:
bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
bcc.options.speed = "-O2 -6"
bcc.options.size = "-O1 -6"
# Configuration for the Visual C/C++ compiler:
#@if vcc:
# @prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"
# @prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"
# @prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"
#@end
#@if windows:
# vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"
#@end
@if vcc:
@prepend_env path r"C:\Programme\Microsoft Visual Studio 9.0\Common7\IDE;"
@prepend_env INCLUDE r"C:\Programme\Microsoft Visual Studio 9.0\VC\include;C:\Programme\Microsoft Visual Studio 9.0\VC\ATLMFC\INCLUDE;C:\Programme\Microsoft SDKs\Windows\v6.0A\Include;"
@prepend_env LIB r"C:\Programme\Microsoft Visual Studio 9.0\VC\lib;C:\Programme\Microsoft Visual Studio 9.0\SDK\v2.0\Lib;C:\Programme\Microsoft SDKs\Windows\v6.0A\Lib;"
passl: r"/F8388608" # set the stack size to 8 MB
@end
@if windows:
vcc.path = r"C:\Programme\Microsoft Visual Studio 9.0\VC\bin"
@end
vcc.options.debug = "/RTC1 /ZI"
vcc.options.always = "/nologo"
vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
vcc.options.size = "/O1 /G7"
# Configuration for the Watcom C/C++ compiler:
@if windows:
wcc.path = r"C:\eigenes\compiler\watcom\binnt"
@end
wcc.options.debug = "-d2"
wcc.options.always = "-6 -zw -w-"
wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
# Configuration for the GNU C/C++ compiler:
@if windows:
gcc.path = r"C:\eigenes\compiler\mingw\bin"
@end
gcc.options.debug = "-g"
@if macosx:
gcc.options.always = "-w -fasm-blocks"
@else:
gcc.options.always = "-w"
@end
gcc.options.speed = "-O3 -ffast-math"
gcc.options.size = "-Os -ffast-math"
# Configuration for the Digital Mars C/C++ compiler:
@if windows:
dmc.path = r"C:\eigenes\compiler\d\dm\bin"
@end
dmc.options.debug = "-g"
dmc.options.always = "-Jm"
dmc.options.speed = "-ff -o -6"
dmc.options.size = "-ff -o -6"
# Configuration for the LCC compiler:
@if windows:
lcc.path = r"C:\eigenes\compiler\lcc\bin"
@end
lcc.options.debug = "-g5"
lcc.options.always = "-e1"
lcc.options.speed = "-O -p6"
lcc.options.size = "-O -p6"
# Configuration for the Tiny C Compiler:
@if windows:
tcc.path = r"C:\Eigenes\compiler\tcc-0.9.23\tcc"
tcc.options.always = r"-IC:\Eigenes\compiler\tcc-0.9.23\include " &
r"-IC:\Eigenes\compiler\tcc-0.9.23\include\winapi"
@end
tcc.options.debug = ""
tcc.options.speed = ""
tcc.options.size = ""
# Configuration for the Pelles C compiler:
@if windows:
pcc.path = r"C:\eigenes\compiler\pellesc\bin"
@end
pcc.options.debug = "-Zi"
pcc.options.always = "-Ze"
pcc.options.speed = "-Ox"
pcc.options.size = "-Os"
@if windows:
icc.path = r"c:\eignes\compiler\icc\bin"
@end
icc.options.debug = "-g"
icc.options.always = "-w"
icc.options.speed = "-O3 -ffast-math"
icc.options.size = "-Os -ffast-math"
@write "used special config file"
@if ecmascript:
@write "Target is ECMAScript! No unsafe features are allowed!"
@end

1
dist/empty.txt vendored
View File

@@ -1 +0,0 @@
This file keeps several tools from deleting this subdirectory.

20
doc/mytest.cfg Normal file
View File

@@ -0,0 +1,20 @@
# This is a comment.
; this too.
[Common]
cc=gcc # '=' and ':' are the same
--verbose
[Windows]
isConsoleApplication=False ; another comment
[Posix]
isConsoleApplication=True
key1: "in this string backslash escapes are interpreted\n"
key2: r"in this string not"
key3: """triple quotes strings
are also supported. They may span
multiple lines."""
--"long option with spaces": r"c:\myfiles\test.txt"

24
doc/steps.txt Normal file
View File

@@ -0,0 +1,24 @@
==============================
First steps after installation
==============================
This document explains how to *use* the Nimrod compiler.
Open your favourite text editor and type (or download it
`here <download/code/hallo.nim>`_):
.. code-block:: nimrod
:file: ../tests/hallo.nim
Save this file as ``hallo.nim`` somewhere (I refer to the location as
``$yourloc``). Now open a console and call the Nimrod compiler::
nimrod compile --run $yourloc/hallo
The ``--run`` switch tells Nimrod that it should run the generated
executable after successful compilation. If things don't work,
check if Nimrod's ``bin`` directory is in your path environment
variable. On Windows the directory ``dist\llvm-gcc4.2\bin`` may
also be required in your path.
Note that Nimrod produced a standalone native executable in
``$yourloc`` that you can run without the Nimrod compiler.

8
ide/nimide.gladep Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
<glade-project>
<name></name>
<program_name></program_name>
<gnome_support>FALSE</gnome_support>
</glade-project>

73
lib/base/lex.nim Normal file
View File

@@ -0,0 +1,73 @@
# Lexer generator for Nimrod
# (c) 2008 Andreas Rumpf
# Stress testing for the macro feature
# the syntax that should be supported is:
# template numpostfix =
# '\'' & 'F'|'f'|'i'|'I' & "32"|"64"|"8"|"16"
# template edigits =
# 'e'|'E' & +digits
# tokens(
# tkIdent: +UniIdentStart & *UniIdentRest,
# tkHexNumber: '0' & ('x'|'X') & +hexDigits & ?( numpostfix ),
# tkOctNumber: '0' & ('c'|'C') & +octDigits & ?( numpostfix ),
# tkBinNumber: '0' & ('b'|'B') & +binDigits & ?( numpostfix ),
# tkIntNumber: +digits & ?( numpostfix ),
# tkFloatNumber: +digits & ('.' & +digits & ?(edigits) | edigits) & ?(numpostfix),
#
# )
# actions(
# tkIdent: lookup
# )
#
#
# match inputstream
# of +('A'..'Z' | '_' | 'a'..'z') *('A'..'Z' | '_' | 'a'..'z' | '0'..'9') :
#
# x = inputstream[pos..length]
# of '0' 'x' +('0'..'9' | 'a'..'f' | '_' | 'A'..'F') :
# y = ...
const
AsciiLetter = {'A'..'Z', 'a'..'z'}
uniLetter = AsciiLetter + {'\128'..'\255'}
digits = {'0'..'9'}
hexDigits = {'0'..'9', 'a'..'f', 'A'..'F'}
octDigits = {'0'..'7'}
binDigits = {'0'..'1'}
AsciiIdentStart = AsciiLetter + {'_'}
AsciiIdentRest = AsciiIdentStart + Digits
UniIdentStart = UniLetter + {'_'}
UniIdentRest = UniIdentStart + Digits
# --> if match(s, +AsciiIdentStart & *AsciiIdentRest):
# Regular expressions in Nimrod itself!
# -------------------------------------
#
# 'a' -- matches the character a
# 'a'..'z' -- range operator '-'
# 'A' | 'B' -- alternative operator |
# * 'a' -- prefix * is needed
# + 'a' -- prefix + is needed
# ? 'a' -- prefix ? is needed
# *? prefix is needed
# +? prefix is needed
# letter -- character classes with real names!
# letters
# white
# whites
# any -- any character
# () -- are Nimrod syntax
# ! 'a'-'z'
#
# -- concatentation via proc call:
#
# re('A' 'Z' *word )
macro re(n: expr): expr =
result = newCall("magic_re", x)

12
lib/contnrs.nim Normal file
View File

@@ -0,0 +1,12 @@
# Container library for Nimrod
# Implemented with macros, because generics sucks in many ways
# Data structures for now:
# TTable, TSet, TList
# Algorithms: Trees, hashing,
TTable[key, val, [Algorithm]]
macro TTable(n: typeexpr): typeexpr =

450
lib/ecmas/dom.nim Normal file
View File

@@ -0,0 +1,450 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Declaration of the Document Object Model for the ECMAScript backend.
## (c) 2008 Andreas Rumpf
when not defined(ecmascript):
{.error: "This module only works on the ECMAScript platform".}
type
TEventHandlers* {.importc.} = object of TObject
onabort*: proc (event: ref TEvent)
onblur*: proc (event: ref TEvent)
onchange*: proc (event: ref TEvent)
onclick*: proc (event: ref TEvent)
ondblclick*: proc (event: ref TEvent)
onerror*: proc (event: ref TEvent)
onfocus*: proc (event: ref TEvent)
onkeydown*: proc (event: ref TEvent)
onkeypress*: proc (event: ref TEvent)
onkeyup*: proc (event: ref TEvent)
onload*: proc (event: ref TEvent)
onmousedown*: proc (event: ref TEvent)
onmousemove*: proc (event: ref TEvent)
onmouseout*: proc (event: ref TEvent)
onmouseover*: proc (event: ref TEvent)
onmouseup*: proc (event: ref TEvent)
onreset*: proc (event: ref TEvent)
onselect*: proc (event: ref TEvent)
onsubmit*: proc (event: ref TEvent)
onunload*: proc (event: ref TEvent)
TWindow* {.importc.} = object of TEventHandlers
document*: ref TDocument
event*: ref TEvent
history*: ref THistory
location*: ref TLocation
closed*: bool
defaultStatus*: cstring
innerHeight*, innerWidth*: int
locationbar*: ref TLocationBar
menubar*: ref TMenuBar
name*: cstring
outerHeight*, outerWidth*: int
pageXOffset*, pageYOffset*: int
personalbar*: ref TPersonalBar
scrollbars*: ref TScrollBars
statusbar*: ref TStatusBar
status*: cstring
toolbar*: ref TToolBar
alert*: proc (msg: cstring)
back*: proc ()
blur*: proc ()
captureEvents*: proc (eventMask: int)
clearInterval*: proc (interval: ref TInterval)
clearTimeout*: proc (timeout: ref TTimeOut)
close*: proc ()
confirm*: proc (msg: cstring): bool
disableExternalCapture*: proc ()
enableExternalCapture*: proc ()
find*: proc (text: cstring, caseSensitive = false, backwards = false)
focus*: proc ()
forward*: proc ()
handleEvent*: proc (e: ref TEvent)
home*: proc ()
moveBy*: proc (x, y: int)
moveTo*: proc (x, y: int)
open*: proc (uri, windowname: cstring,
properties: cstring = nil): ref TWindow
print*: proc ()
prompt*: proc (text, default: cstring): cstring
releaseEvents*: proc (eventMask: int)
resizeBy*: proc (x, y: int)
resizeTo*: proc (x, y: int)
routeEvent*: proc (event: ref TEvent)
scrollBy*: proc (x, y: int)
scrollTo*: proc (x, y: int)
setInterval*: proc (code: cstring, pause: int): ref TInterval
setTimeout*: proc (code: cstring, pause: int): ref TTimeOut
stop*: proc ()
frames*: seq[TFrame]
TFrame* {.importc.} = object of TWindow
TDocument* {.importc.} = object of TEventHandlers
alinkColor*: cstring
bgColor*: cstring
charset*: cstring
cookie*: cstring
defaultCharset*: cstring
fgColor*: cstring
lastModified*: cstring
linkColor*: cstring
referrer*: cstring
title*: cstring
URL*: cstring
vlinkColor*: cstring
captureEvents*: proc (eventMask: int)
createAttribute*: proc (identifier: cstring): ref TNode
createElement*: proc (identifier: cstring): ref TNode
createTextNode*: proc (identifier: cstring): ref TNode
getElementById*: proc (id: cstring): ref TNode
getElementsByName*: proc (name: cstring): seq[ref TNode]
getElementsByTagName*: proc (name: cstring): seq[ref TNode]
getSelection*: proc (): cstring
handleEvent*: proc (event: ref TEvent)
open*: proc ()
releaseEvents*: proc (eventMask: int)
routeEvent*: proc (event: ref TEvent)
write*: proc (text: cstring)
writeln*: proc (text: cstring)
anchors*: seq[ref TAnchor]
forms*: seq[ref TForm]
images*: seq[ref TImage]
applets*: seq[ref TApplet]
embeds*: seq[ref TEmbed]
links*: seq[ref TLink]
TLink* {.importc.} = object of TObject
name*: cstring
target*: cstring
text*: cstring
x*: int
y*: int
TEmbed* {.importc.} = object of TObject
height*: int
hspace*: int
name*: cstring
src*: cstring
width*: int
`type`*: cstring
vspace*: int
play*: proc ()
stop*: proc ()
TAnchor* {.importc.} = object of TObject
name*: cstring
text*: cstring
x*, y*: int
TApplet* {.importc.} = object of TObject
TElement* {.importc.} = object of TEventHandlers
checked*: bool
defaultChecked*: bool
defaultValue*: cstring
disabled*: bool
form*: ref TForm
name*: cstring
readOnly*: bool
`type`*: cstring
value*: cstring
blur*: proc ()
click*: proc ()
focus*: proc ()
handleEvent*: proc (event: ref TEvent)
select*: proc ()
options*: seq[ref TOption]
TOption* {.importc.} = object of TObject
defaultSelected*: bool
selected*: bool
selectedIndex*: int
text*: cstring
value*: cstring
TForm* {.importc.} = object of TEventHandlers
action*: cstring
encoding*: cstring
`method`*: cstring
name*: cstring
target*: cstring
handleEvent*: proc (event: ref TEvent)
reset*: proc ()
submit*: proc ()
elements*: seq[ref TElement]
TImage* {.importc.} = object of TEventHandlers
border*: int
complete*: bool
height*: int
hspace*: int
lowsrc*: cstring
name*: cstring
src*: cstring
vspace*: int
width*: int
handleEvent*: proc (event: ref TEvent)
TNodeType* = enum
ElementNode = 1,
AttributeNode,
TextNode,
CDATANode,
EntityRefNode,
EntityNode,
ProcessingInstructionNode,
CommentNode,
DocumentNode,
DocumentTypeNode,
DocumentFragmentNode,
NotationNode
TNode* {.importc.} = object of TObject
attributes*: seq[ref TNode]
childNodes*: seq[ref TNode]
data*: cstring
firstChild*: ref TNode
lastChild*: ref TNode
nextSibling*: ref TNode
nodeName*: cstring
nodeType*: TNodeType
nodeValue*: cstring
parentNode*: ref TNode
previousSibling*: ref TNode
appendChild*: proc (child: ref TNode)
appendData*: proc (data: cstring)
cloneNode*: proc (copyContent: bool)
deleteData*: proc (start, len: int)
getAttribute*: proc (attr: cstring): cstring
getAttributeNode*: proc (attr: cstring): ref TNode
getElementsByTagName*: proc (): seq[ref TNode]
hasChildNodes*: proc (): bool
insertBefore*: proc (newNode, before: ref TNode)
insertData*: proc (position: int, data: cstring)
removeAttribute*: proc (attr: cstring)
removeAttributeNode*: proc (attr: ref TNode)
removeChild*: proc (child: ref TNode)
replaceChild*: proc (newNode, oldNode: ref TNode)
replaceData*: proc (start, len: int, text: cstring)
setAttribute*: proc (name, value: cstring)
setAttributeNode*: proc (attr: ref TNode)
style*: ref TStyle
TStyle* {.importc.} = object of TObject
background*: cstring
backgroundAttachment*: cstring
backgroundColor*: cstring
backgroundImage*: cstring
backgroundPosition*: cstring
backgroundRepeat*: cstring
border*: cstring
borderBottom*: cstring
borderBottomColor*: cstring
borderBottomStyle*: cstring
borderBottomWidth*: cstring
borderColor*: cstring
borderLeft*: cstring
borderLeftColor*: cstring
borderLeftStyle*: cstring
borderLeftWidth*: cstring
borderRight*: cstring
borderRightColor*: cstring
borderRightStyle*: cstring
borderRightWidth*: cstring
borderStyle*: cstring
borderTop*: cstring
borderTopColor*: cstring
borderTopStyle*: cstring
borderTopWidth*: cstring
borderWidth*: cstring
bottom*: cstring
captionSide*: cstring
clear*: cstring
clip*: cstring
color*: cstring
cursor*: cstring
direction*: cstring
display*: cstring
emptyCells*: cstring
cssFloat*: cstring
font*: cstring
fontFamily*: cstring
fontSize*: cstring
fontStretch*: cstring
fontStyle*: cstring
fontVariant*: cstring
fontWeight*: cstring
height*: cstring
left*: cstring
letterSpacing*: cstring
lineHeight*: cstring
listStyle*: cstring
listStyleImage*: cstring
listStylePosition*: cstring
listStyleType*: cstring
margin*: cstring
marginBottom*: cstring
marginLeft*: cstring
marginRight*: cstring
marginTop*: cstring
maxHeight*: cstring
maxWidth*: cstring
minHeight*: cstring
minWidth*: cstring
overflow*: cstring
padding*: cstring
paddingBottom*: cstring
paddingLeft*: cstring
paddingRight*: cstring
paddingTop*: cstring
pageBreakAfter*: cstring
pageBreakBefore*: cstring
position*: cstring
right*: cstring
scrollbar3dLightColor*: cstring
scrollbarArrowColor*: cstring
scrollbarBaseColor*: cstring
scrollbarDarkshadowColor*: cstring
scrollbarFaceColor*: cstring
scrollbarHighlightColor*: cstring
scrollbarShadowColor*: cstring
scrollbarTrackColor*: cstring
tableLayout*: cstring
textAlign*: cstring
textDecoration*: cstring
textIndent*: cstring
textTransform*: cstring
top*: cstring
verticalAlign*: cstring
visibility*: cstring
width*: cstring
wordSpacing*: cstring
zIndex*: int
getAttribute*: proc (attr: cstring, caseSensitive=false): cstring
removeAttribute*: proc (attr: cstring, caseSensitive=false)
setAttribute*: proc (attr, value: cstring, caseSensitive=false)
TEvent* {.importc.} = object of TObject
altKey*, ctrlKey*, shiftKey*: bool
button*: int
clientX*, clientY*: int
keyCode*: int
layerX*, layerY*: int
modifiers*: int
ALT_MASK*, CONTROL_MASK*, SHIFT_MASK*, META_MASK*: int
offsetX*, offsetY*: int
pageX*, pageY*: int
screenX*, screenY*: int
which*: int
`type`*: cstring
x*, y*: int
ABORT*: int
BLUR*: int
CHANGE*: int
CLICK*: int
DBLCLICK*: int
DRAGDROP*: int
ERROR*: int
FOCUS*: int
KEYDOWN*: int
KEYPRESS*: int
KEYUP*: int
LOAD*: int
MOUSEDOWN*: int
MOUSEMOVE*: int
MOUSEOUT*: int
MOUSEOVER*: int
MOUSEUP*: int
MOVE*: int
RESET*: int
RESIZE*: int
SELECT*: int
SUBMIT*: int
UNLOAD*: int
TLocation* {.importc.} = object of TObject
hash*: cstring
host*: cstring
hostname*: cstring
href*: cstring
pathname*: cstring
port*: cstring
protocol*: cstring
search*: cstring
reload*: proc ()
replace*: proc (s: cstring)
THistory* {.importc.} = object of TObject
length*: int
back*: proc ()
forward*: proc ()
go*: proc (pagesToJump: int)
TNavigator* {.importc.} = object of TObject
appCodeName*: cstring
appName*: cstring
appVersion*: cstring
cookieEnabled*: bool
language*: cstring
platform*: cstring
userAgent*: cstring
javaEnabled*: proc (): bool
mimeTypes*: seq[ref TMimeType]
TPlugin* {.importc.} = object of TObject
description*: cstring
filename*: cstring
name*: cstring
TMimeType* {.importc.} = object of TObject
description*: cstring
enabledPlugin*: ref TPlugin
suffixes*: seq[cstring]
`type`*: cstring
TLocationBar* {.importc.} = object of TObject
visible*: bool
TMenuBar* = TLocationBar
TPersonalBar* = TLocationBar
TScrollBars* = TLocationBar
TToolBar* = TLocationBar
TStatusBar* = TLocationBar
TScreen* {.importc.} = object of TObject
availHeight*: int
availWidth*: int
colorDepth*: int
height*: int
pixelDepth*: int
width*: int
TTimeOut* {.importc.} = object of TObject
TInterval* {.importc.} = object of TObject
var
window* {.importc, nodecl.}: ref TWindow
document* {.importc, nodecl.}: ref TDocument
navigator* {.importc, nodecl.}: ref TNavigator
screen* {.importc, nodecl.}: ref TScreen
proc decodeURI*(uri: cstring): cstring {.importc, nodecl.}
proc encodeURI*(uri: cstring): cstring {.importc, nodecl.}
proc escape*(uri: cstring): cstring {.importc, nodecl.}
proc unescape*(uri: cstring): cstring {.importc, nodecl.}
proc decodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
proc encodeURIComponent*(uri: cstring): cstring {.importc, nodecl.}
proc isFinite(x: biggestFloat): bool {.importc, nodecl.}
proc isNaN(x: biggestFloat): bool {.importc, nodecl.}
proc parseFloat(s: cstring): biggestFloat {.importc, nodecl.}
proc parseInt(s: cstring): int {.importc, nodecl.}

527
lib/ecmasys.nim Normal file
View File

@@ -0,0 +1,527 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Stubs for the GC interface:
proc GC_disable() = nil
proc GC_enable() = nil
proc GC_fullCollect() = nil
proc GC_setStrategy(strategy: TGC_Strategy) = nil
proc GC_enableMarkAndSweep() = nil
proc GC_disableMarkAndSweep() = nil
proc getOccupiedMem(): int = return -1
proc getFreeMem(): int = return -1
proc getTotalMem(): int = return -1
proc alert(s: cstring) {.importc, nodecl.}
type
PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point
exc: ref E_Base
PCallFrame = ptr TCallFrame
TCallFrame {.importc, nodecl, final.} = object
prev: PCallFrame
procname: CString
line: int # current line number
filename: CString
var
framePtr {.importc, nodecl, volatile.}: PCallFrame
excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
# list of exception handlers
# a global variable for the root of all try blocks
{.push stacktrace: off.}
proc nimBoolToStr(x: bool): string {.compilerproc.} =
if x: result = "true"
else: result = "false"
proc nimCharToStr(x: char): string {.compilerproc.} =
result = newString(1)
result[0] = x
proc getCurrentExceptionMsg(): string =
if excHandler != nil: return $excHandler.exc.msg
return ""
proc auxWriteStackTrace(f: PCallFrame): string =
type
TTempFrame = tuple[procname: CString, line: int]
var
it = f
i = 0
total = 0
tempFrames: array [0..63, TTempFrame]
while it != nil and i <= high(tempFrames):
tempFrames[i].procname = it.procname
tempFrames[i].line = it.line
inc(i)
inc(total)
it = it.prev
while it != nil:
inc(total)
it = it.prev
result = ""
# if the buffer overflowed print '...':
if total != i:
add(result, "(")
add(result, $(total-i))
add(result, " calls omitted) ...\n")
for j in countdown(i-1, 0):
add(result, tempFrames[j].procname)
if tempFrames[j].line > 0:
add(result, ", line: ")
add(result, $tempFrames[j].line)
add(result, "\n")
proc rawWriteStackTrace(): string =
if framePtr == nil:
result = "No stack traceback available\n"
else:
result = "Traceback (most recent call last)\n"& auxWriteStackTrace(framePtr)
framePtr = nil
proc raiseException(e: ref E_Base, ename: cstring) {.compilerproc, pure.} =
e.name = ename
if excHandler != nil:
excHandler.exc = e
else:
var buf = rawWriteStackTrace()
if e.msg != nil and e.msg[0] != '\0':
add(buf, "Error: unhandled exception: ")
add(buf, e.msg)
else:
add(buf, "Error: unhandled exception")
add(buf, " [")
add(buf, ename)
add(buf, "]\n")
alert(buf)
asm """throw `e`;"""
proc reraiseException() =
if excHandler == nil:
raise newException(ENoExceptionToReraise, "no exception to reraise")
else:
asm """throw excHandler.exc;"""
proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
raise newException(EOverflow, "over- or underflow")
proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} =
raise newException(EDivByZero, "divison by zero")
proc raiseRangeError() {.compilerproc, noreturn.} =
raise newException(EOutOfRange, "value out of range")
proc raiseIndexError() {.compilerproc, noreturn.} =
raise newException(EInvalidIndex, "index out of bounds")
proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
raise newException(EInvalidField, f & " is not accessible")
proc SetConstr() {.varargs, pure, compilerproc.} =
asm """
var result = {};
for (var i = 0; i < arguments.length; ++i) {
var x = arguments[i];
if (typeof(x) == "object") {
for (var j = x[0]; j <= x[1]; ++j) {
result[j] = true;
}
} else {
result[x] = true;
}
}
return result;
"""
proc cstrToNimstr(c: cstring): string {.pure, compilerproc.} =
asm """
var result = [];
for (var i = 0; i < `c`.length; ++i) {
result[i] = `c`.charCodeAt(i);
}
result[result.length] = 0; // terminating zero
return result;
"""
proc toEcmaStr(s: string): cstring {.pure, compilerproc.} =
asm """
var len = `s`.length-1;
var result = new Array(len);
var fcc = String.fromCharCode;
for (var i = 0; i < len; ++i) {
result[i] = fcc(`s`[i]);
}
return result.join("");
"""
proc mnewString(len: int): string {.pure, compilerproc.} =
asm """
var result = new Array(`len`+1);
result[0] = 0;
result[`len`] = 0;
return result;
"""
proc SetCard(a: int): int {.compilerproc, pure.} =
# argument type is a fake
asm """
var result = 0;
for (var elem in `a`) { ++result; }
return result;
"""
proc SetEq(a, b: int): bool {.compilerproc, pure.} =
asm """
for (var elem in `a`) { if (!`b`[elem]) return false; }
for (var elem in `b`) { if (!`a`[elem]) return false; }
return true;
"""
proc SetLe(a, b: int): bool {.compilerproc, pure.} =
asm """
for (var elem in `a`) { if (!`b`[elem]) return false; }
return true;
"""
proc SetLt(a, b: int): bool {.compilerproc.} =
result = SetLe(a, b) and not SetEq(a, b)
proc SetMul(a, b: int): int {.compilerproc, pure.} =
asm """
var result = {};
for (var elem in `a`) {
if (`b`[elem]) { result[elem] = true; }
}
return result;
"""
proc SetPlus(a, b: int): int {.compilerproc, pure.} =
asm """
var result = {};
for (var elem in `a`) { result[elem] = true; }
for (var elem in `b`) { result[elem] = true; }
return result;
"""
proc SetMinus(a, b: int): int {.compilerproc, pure.} =
asm """
var result = {};
for (var elem in `a`) {
if (!`b`[elem]) { result[elem] = true; }
}
return result;
"""
proc cmpStrings(a, b: string): int {.pure, compilerProc.} =
asm """
if (`a` == `b`) return 0;
if (!`a`) return -1;
if (!`b`) return 1;
for (var i = 0; i < `a`.length-1; ++i) {
var result = `a`[i] - `b`[i];
if (result != 0) return result;
}
return 0;
"""
proc cmp(x, y: string): int = return cmpStrings(x, y)
proc eqStrings(a, b: string): bool {.pure, compilerProc.} =
asm """
if (`a == `b`) return true;
if ((!`a`) || (!`b`)) return false;
var alen = `a`.length;
if (alen != `b`.length) return false;
for (var i = 0; i < alen; ++i)
if (`a`[i] != `b`[i]) return false;
return true;
"""
type
TDocument {.importc.} = object of TObject
write: proc (text: cstring)
writeln: proc (text: cstring)
createAttribute: proc (identifier: cstring): ref TNode
createElement: proc (identifier: cstring): ref TNode
createTextNode: proc (identifier: cstring): ref TNode
getElementById: proc (id: cstring): ref TNode
getElementsByName: proc (name: cstring): seq[ref TNode]
getElementsByTagName: proc (name: cstring): seq[ref TNode]
TNodeType* = enum
ElementNode = 1,
AttributeNode,
TextNode,
CDATANode,
EntityRefNode,
EntityNode,
ProcessingInstructionNode,
CommentNode,
DocumentNode,
DocumentTypeNode,
DocumentFragmentNode,
NotationNode
TNode* {.importc.} = object of TObject
attributes*: seq[ref TNode]
childNodes*: seq[ref TNode]
data*: cstring
firstChild*: ref TNode
lastChild*: ref TNode
nextSibling*: ref TNode
nodeName*: cstring
nodeType*: TNodeType
nodeValue*: cstring
parentNode*: ref TNode
previousSibling*: ref TNode
appendChild*: proc (child: ref TNode)
appendData*: proc (data: cstring)
cloneNode*: proc (copyContent: bool)
deleteData*: proc (start, len: int)
getAttribute*: proc (attr: cstring): cstring
getAttributeNode*: proc (attr: cstring): ref TNode
getElementsByTagName*: proc (): seq[ref TNode]
hasChildNodes*: proc (): bool
insertBefore*: proc (newNode, before: ref TNode)
insertData*: proc (position: int, data: cstring)
removeAttribute*: proc (attr: cstring)
removeAttributeNode*: proc (attr: ref TNode)
removeChild*: proc (child: ref TNode)
replaceChild*: proc (newNode, oldNode: ref TNode)
replaceData*: proc (start, len: int, text: cstring)
setAttribute*: proc (name, value: cstring)
setAttributeNode*: proc (attr: ref TNode)
var
document {.importc, nodecl.}: ref TDocument
proc ewriteln(x: cstring) =
var node = document.getElementsByTagName("body")[0]
if node != nil:
node.appendChild(document.createTextNode(x))
node.appendChild(document.createElement("br"))
else:
raise newException(EInvalidValue, "<body> element does not exist yet!")
proc echo*(x: int) = ewriteln($x)
proc echo*(x: float) = ewriteln($x)
proc echo*(x: bool) = ewriteln(if x: cstring("true") else: cstring("false"))
proc echo*(x: string) = ewriteln(x)
proc echo*(x: cstring) = ewriteln(x)
proc echo[Ty](x: Ty) =
echo(x)
# Arithmetic:
proc addInt(a, b: int): int {.pure, compilerproc.} =
asm """
var result = `a` + `b`;
if (result > 2147483647 || result < -2147483648) raiseOverflow();
return result;
"""
proc subInt(a, b: int): int {.pure, compilerproc.} =
asm """
var result = `a` - `b`;
if (result > 2147483647 || result < -2147483648) raiseOverflow();
return result;
"""
proc mulInt(a, b: int): int {.pure, compilerproc.} =
asm """
var result = `a` * `b`;
if (result > 2147483647 || result < -2147483648) raiseOverflow();
return result;
"""
proc divInt(a, b: int): int {.pure, compilerproc.} =
asm """
if (`b` == 0) raiseDivByZero();
if (`b` == -1 && `a` == 2147483647) raiseOverflow();
return Math.floor(`a` / `b`);
"""
proc modInt(a, b: int): int {.pure, compilerproc.} =
asm """
if (`b` == 0) raiseDivByZero();
if (`b` == -1 && `a` == 2147483647) raiseOverflow();
return Math.floor(`a` % `b`);
"""
proc addInt64(a, b: int): int {.pure, compilerproc.} =
asm """
var result = `a` + `b`;
if (result > 9223372036854775807
|| result < -9223372036854775808) raiseOverflow();
return result;
"""
proc subInt64(a, b: int): int {.pure, compilerproc.} =
asm """
var result = `a` - `b`;
if (result > 9223372036854775807
|| result < -9223372036854775808) raiseOverflow();
return result;
"""
proc mulInt64(a, b: int): int {.pure, compilerproc.} =
asm """
var result = `a` * `b`;
if (result > 9223372036854775807
|| result < -9223372036854775808) raiseOverflow();
return result;
"""
proc divInt64(a, b: int): int {.pure, compilerproc.} =
asm """
if (`b` == 0) raiseDivByZero();
if (`b` == -1 && `a` == 9223372036854775807) raiseOverflow();
return Math.floor(`a` / `b`);
"""
proc modInt64(a, b: int): int {.pure, compilerproc.} =
asm """
if (`b` == 0) raiseDivByZero();
if (`b` == -1 && `a` == 9223372036854775807) raiseOverflow();
return Math.floor(`a` % `b`);
"""
proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
proc internalAssert(file: cstring, line: int) {.pure, compilerproc.} =
var
e: ref EAssertionFailed
new(e)
asm """`e`.message = "[Assertion failure] file: "+`file`+", line: "+`line`"""
raise e
include hti
proc isFatPointer(ti: PNimType): bool =
# This has to be consistens with the code generator!
return ti.base.kind notin {tyRecord, tyRecordConstr, tyObject,
tyArray, tyArrayConstr, tyPureObject, tyTuple,
tyEmptySet, tyOpenArray, tySet, tyVar, tyRef, tyPtr}
proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} =
case n.kind
of nkNone: assert(false)
of nkSlot:
asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);"
of nkList:
for i in 0..n.len-1:
NimCopyAux(dest, src, n.sons[i])
of nkCase:
asm """
`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);
for (var i = 0; i < `n`.sons.length; ++i) {
NimCopyAux(`dest`, `src`, `n`.sons[i][1]);
}
"""
proc NimCopy(x: pointer, ti: PNimType): pointer =
case ti.kind
of tyPtr, tyRef, tyVar, tyNil:
if not isFatPointer(ti):
result = x
else:
asm """
`result` = [null, 0];
`result`[0] = `x`[0];
`result`[1] = `x`[1];
"""
of tyEmptySet, tySet:
asm """
`result` = {};
for (var key in `x`) { `result`[key] = `x`[key]; }
"""
of tyPureObject, tyTuple, tyObject:
if ti.base != nil: result = NimCopy(x, ti.base)
elif ti.kind == tyObject:
asm "`result` = {m_type: `ti`};"
else:
asm "`result` = {};"
NimCopyAux(result, x, ti.node)
of tySequence, tyArrayConstr, tyOpenArray, tyArray:
asm """
`result` = new Array(`x`.length);
for (var i = 0; i < `x`.length; ++i) {
`result`[i] = NimCopy(`x`[i], `ti`.base);
}
"""
of tyString:
asm "`result` = `x`.slice(0);"
else:
result = x
proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
pure, compilerproc.} =
# types are fake
asm """
var result = new Array(`len`);
for (var i = 0; i < `len`; ++i) result[i] = NimCopy(`value`, `typ`);
return result;
"""
proc chckIndx(i, a, b: int): int {.compilerproc.} =
if i >= a and i <= b: return i
else: raiseIndexError()
proc chckRange(i, a, b: int): int {.compilerproc.} =
if i >= a and i <= b: return i
else: raiseRangeError()
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
# checks if obj is of type subclass:
var x = obj
if x == subclass: return # optimized fast path
while x != subclass:
if x == nil:
raise newException(EInvalidObjectConversion, "invalid object conversion")
x = x.base
{.pop.}
#proc AddU($1, $2)
#SubU($1, $2)
#MulU($1, $2)
#DivU($1, $2)
#ModU($1, $2)
#AddU64($1, $2)
#SubU64($1, $2)
#MulU64($1, $2)
#DivU64($1, $2)
#ModU64($1, $2)
#LeU($1, $2)
#LtU($1, $2)
#LeU64($1, $2)
#LtU64($1, $2)
#Ze($1)
#Ze64($1)
#ToU8($1)
#ToU16($1)
#ToU32($1)
#NegInt($1)
#NegInt64($1)
#AbsInt($1)
#AbsInt64($1)

170
lib/generics.nim Normal file
View File

@@ -0,0 +1,170 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains basic abstract data types.
type
TListItem[T] = object
next, prev: ref TListItem[T]
data: T
TList*[T] = ref TListItem[T]
# TIndex*[T] = object
#proc succ*[T](i: TIndex[T]): TIndex[T] =
# result = i.next
#proc pred*[T](i: TIndex[T]): TIndex[T] =
# result = i.prev
#proc getIndex*[T](c: TList[T]): TIndex[TList[T]] =
# return c
proc init*[T](c: var TList[T]) {.inline.} =
c = nil
iterator items*[T](c: TList[T]): var T {.inline.} =
var it = c
while it != nil:
yield it.data
it = it.next
proc add*[T](c: var TList[T], item: T) {.inline.} =
var it: ref TListItem[T]
new(it)
it.data = item
it.prev = c.prev
it.next = c.next
c = it
proc incl*[T](c: var TList[T], item: T) =
for i in items(c):
if i == item: return
add(c, item)
proc excl*[T](c: var TList[T], item: T) =
var it: TList[T] = c
while it != nil:
if it.data == item:
# remove from list
it = it.next
proc del*[T](c: var TList[T], item: T) {.inline.} = excl(c, item)
proc hash*(p: pointer): int {.inline.} =
# Returns the hash value of a pointer. This is very fast.
return cast[TAddress](p) shr 3
proc hash*(x: int): int {.inline.} = return x
proc hash*(x: char): int {.inline.} = return ord(x)
proc hash*(x: bool): int {.inline.} = return ord(x)
proc hash*(s: string): int =
# The generic hash table implementation work on a type `T` that has a hash
# proc. Predefined for string, pointers, int, char, bool.
var h = 0
for i in 0..s.len-1:
h = h +% Ord(s[i])
h = h +% h shl 10
h = h xor (h shr 6)
h = h +% h shl 3
h = h xor (h shr 11)
h = h +% h shl 15
result = h
proc isNil*(x: int): bool {.inline.} = return x == low(int)
proc nilValue*(x: int): int {.inline.} = return low(int)
proc nilValue*(x: pointer): pointer {.inline.} = return nil
proc nilValue*(x: string): string {.inline.} = return nil
proc nilValue*[T](x: seq[T]): seq[T] {.inline.} = return nil
proc nilValue*(x: float): float {.inline.} = return NaN
proc mustRehash(len, counter: int): bool =
assert(len > counter)
result = (len * 2 < counter * 3) or (len-counter < 4)
proc nextTry(h, maxHash: int): int {.inline.} =
return ((5*%h) +% 1) and maxHash
type
TPair*[TKey, TValue] = tuple[key: TKey, val: TValue]
TTable*[TKey, TValue] =
object of TObject ## A table which stores (key, value)
## pairs. The used algorithm is hashing.
d: seq[TPair[TKey, TValue]]
counter: natural
const
growthFactor = 2 # must be power of two
proc init*[TKey, TValue](t: var TTable[TKey, TValue], capacity: natural = 32) =
t.d = [] # XXX
setLen(t.d, capacity)
proc len*[TKey, TValue](t: TTable[TKey, TValue]): natural = return t.counter
iterator pairs*[TKey,TValue](t: TTable[TKey,TValue]): TPair[TKey, TValue] =
for i in 0..t.d.len-1:
if not isNil(t.d[i].key):
yield (t.d[i].key, t.d[i].val)
proc TableRawGet[TKey, TValue](t: TTable[TKey, TValue], key: TKey): int =
var h = hash(key) and high(t.d)
while not isNil(t.d[h].key):
if t.d[h].key == key: return h
h = nextTry(h, high(t.d))
return -1
proc `[]`*[TKey, TValue](t: TTable[TKey, TValue], key: TKey): TValue =
var index = TableRawGet(t, key)
return if index >= 0: t.d[index].val else: nilValue(t.d[0].val)
proc TableRawInsert[TKey, TValue](data: var seq[TPair[TKey, TValue]],
key: TKey, val: TValue) =
var h = hash(key) and high(data)
while not isNil(data[h].key):
assert(data[h].key != key)
h = nextTry(h, high(data))
assert(isNil(data[h].key))
data[h].key = key
data[h].val = val
proc TableEnlarge[TKey, TValue](t: var TTable[TKey, TValue]) =
var n: seq[TPair[TKey,TValue]] = []
setLen(n, len(t.d) * growthFactor) # XXX
for i in 0..high(t.d):
if not isNil(t.d[i].key):
TableRawInsert(n, t.d[i].key, t.d[i].val)
swap(t.d, n)
proc `[]=`*[TKey, TValue](t: var TTable[TKey, TValue], key: TKey, val: TValue) =
var index = TableRawGet(t, key)
if index >= 0:
t.d[index].val = val
else:
if mustRehash(len(t.d), t.counter): TableEnlarge(t)
TableRawInsert(t.d, key, val)
inc(t.counter)
proc add*[TKey, TValue](t: var TTable[TKey, TValue], key: TKey, val: TValue) =
if mustRehash(len(t.d), t.counter): TableEnlarge(t)
TableRawInsert(t.d, key, val)
inc(t.counter)
proc test =
var
t: TTable[string, int]
init(t)
t["key1"] = 1
t["key2"] = 2
t["key3"] = 3
for key, val in pairs(t):
echo(key & " = " & $val)
test()

97
lib/hashes.nim Normal file
View File

@@ -0,0 +1,97 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements efficient computations of hash values for diverse
## Nimrod types.
import
strutils
type
THash* = int ## a hash value; hash tables using these values should
## always have a size of a power of two and can use the ``and``
## operator instead of ``mod`` for truncation of the hash value.
proc concHash(h: THash, val: int): THash {.inline.} =
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
proc finishHash(h: THash): THash {.inline.} =
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
proc hashData*(Data: Pointer, Size: int): THash =
## hashes an array of bytes of size `size`
var
h: THash
p: cstring
i, s: int
h = 0
p = cast[cstring](Data)
i = 0
s = size
while s > 0:
h = concHash(h, ord(p[i]))
Inc(i)
Dec(s)
result = finishHash(h)
proc hash*(x: Pointer): THash {.inline.} =
## efficient hashing of pointers
result = (cast[THash](x)) shr 3 # skip the alignment
proc hash*(x: int): THash {.inline.} =
## efficient hashing of integers
result = x
proc hash*(x: int64): THash {.inline.} =
## efficient hashing of integers
result = toU32(x)
proc hash*(x: char): THash {.inline.} =
## efficient hashing of characters
result = ord(x)
proc hash*(x: string): THash =
## efficient hashing of strings
var h: THash
h = 0
for i in 0..x.len-1:
h = concHash(h, ord(x[i]))
result = finishHash(h)
proc hashIgnoreStyle*(x: string): THash =
## efficient hashing of strings; style is ignored
var
h: THash
c: Char
h = 0
for i in 0..x.len-1:
c = x[i]
if c == '_':
continue # skip _
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = concHash(h, ord(c))
result = finishHash(h)
proc hashIgnoreCase*(x: string): THash =
## efficient hashing of strings; case is ignored
var
h: THash
c: Char
h = 0
for i in 0..x.len-1:
c = x[i]
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = concHash(h, ord(c))
result = finishHash(h)

186
lib/lexbase.nim Normal file
View File

@@ -0,0 +1,186 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base object of a lexer with efficient buffer
## handling. In fact I believe that this is the most efficient method of
## buffer handling that exists! Only at line endings checks are necessary
## if the buffer needs refilling.
import
strutils
const
EndOfFile* = '\0' ## end of file marker
# A little picture makes everything clear :-)
# buf:
# "Example Text\n ha!" bufLen = 17
# ^pos = 0 ^ sentinel = 12
#
NewLines* = {'\c', '\L'}
type
TBaseLexer* = object of TObject ## the base lexer. Inherit your lexer from
## this object.
bufpos*: int ## the current position within the buffer
buf*: cstring ## the buffer itself
bufLen*: int ## length of buffer in characters
f*: tfile ## the file that is read
LineNumber*: int ## the current line number
sentinel: int
lineStart: int # index of last line start in buffer
fileOpened: bool
proc initBaseLexer*(L: var TBaseLexer, filename: string, bufLen: int = 8192): bool
## inits the TBaseLexer object with a file to scan
proc initBaseLexerFromBuffer*(L: var TBaseLexer, buffer: string)
## inits the TBaseLexer with a buffer to scan
proc deinitBaseLexer*(L: var TBaseLexer)
## deinitializes the base lexer. This needs to be called to close the file.
proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
## retrieves the current line.
proc getColNumber*(L: TBaseLexer, pos: int): int
## retrieves the current column.
proc HandleCR*(L: var TBaseLexer, pos: int): int
## Call this if you scanned over '\c' in the buffer; it returns the the
## position to continue the scanning from. `pos` must be the position
## of the '\c'.
proc HandleLF*(L: var TBaseLexer, pos: int): int
## Call this if you scanned over '\L' in the buffer; it returns the the
## position to continue the scanning from. `pos` must be the position
## of the '\L'.
# implementation
const
chrSize = sizeof(char)
proc deinitBaseLexer(L: var TBaseLexer) =
dealloc(L.buf)
if L.fileOpened: closeFile(L.f)
proc FillBuffer(L: var TBaseLexer) =
var
charsRead, toCopy, s: int # all are in characters,
# not bytes (in case this
# is not the same)
oldBufLen: int
# we know here that pos == L.sentinel, but not if this proc
# is called the first time by initBaseLexer()
assert(L.sentinel < L.bufLen)
toCopy = L.BufLen - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize) # "moveMem" handles overlapping regions
charsRead = ReadBuffer(L.f, addr(L.buf[toCopy]), (L.sentinel + 1) * chrSize) div
chrSize
s = toCopy + charsRead
if charsRead < L.sentinel + 1:
L.buf[s] = EndOfFile # set end marker
L.sentinel = s
else:
# compute sentinel:
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.bufLen)
while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
L.sentinel = s
break
else:
# rather than to give up here because the line is too long,
# double the buffer's size and try again:
oldBufLen = L.BufLen
L.bufLen = L.BufLen * 2
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
assert(L.bufLen - oldBuflen == oldBufLen)
charsRead = ReadBuffer(L.f, addr(L.buf[oldBufLen]), oldBufLen * chrSize) div
chrSize
if charsRead < oldBufLen:
L.buf[oldBufLen + charsRead] = EndOfFile
L.sentinel = oldBufLen + charsRead
break
s = L.bufLen - 1
proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
assert(pos <= L.sentinel)
if pos < L.sentinel:
result = pos + 1 # nothing to do
else:
fillBuffer(L)
L.bufpos = 0 # XXX: is this really correct?
result = 0
L.lineStart = result
proc HandleCR(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == '\c')
inc(L.linenumber)
result = fillBaseLexer(L, pos)
if L.buf[result] == '\L':
result = fillBaseLexer(L, result)
proc HandleLF(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == '\L')
inc(L.linenumber)
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
proc skip_UTF_8_BOM(L: var TBaseLexer) =
if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
inc(L.bufpos, 3)
inc(L.lineStart, 3)
proc initBaseLexer(L: var TBaseLexer, filename: string, bufLen: int = 8192): bool =
assert(bufLen > 0)
L.bufpos = 0
L.bufLen = bufLen
L.buf = cast[cstring](alloc(bufLen * chrSize))
L.sentinel = bufLen - 1
L.lineStart = 0
L.linenumber = 1 # lines start at 1
L.fileOpened = openFile(L.f, filename)
result = L.fileOpened
if result:
fillBuffer(L)
skip_UTF_8_BOM(L)
proc initBaseLexerFromBuffer(L: var TBaseLexer, buffer: string) =
L.bufpos = 0
L.bufLen = len(buffer) + 1
L.buf = cast[cstring](alloc(L.bufLen * chrSize))
L.sentinel = L.bufLen - 1
L.lineStart = 0
L.linenumber = 1 # lines start at 1
L.fileOpened = false
if L.bufLen > 0:
copyMem(L.buf, cast[pointer](buffer), L.bufLen)
L.buf[L.bufLen - 1] = EndOfFile
else:
L.buf[0] = EndOfFile
skip_UTF_8_BOM(L)
proc getColNumber(L: TBaseLexer, pos: int): int =
result = pos - L.lineStart
assert(result >= 0)
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
var i: int
result = ""
i = L.lineStart
while not (L.buf[i] in {'\c', '\L', EndOfFile}):
add(result, L.buf[i])
inc(i)
add(result, "\n")
if marker:
add(result, RepeatChar(getColNumber(L, L.bufpos)) & "^\n")

176
lib/macros.nim Normal file
View File

@@ -0,0 +1,176 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains the interface to the compiler's abstract syntax tree.
## Abstract syntax trees should be modified in macros.
#[[[cog
#def toEnum(name, elems, prefix):
# body = ""
# counter = 0
# for e in elems:
# if counter % 4 == 0: p = "\n "
# else: p = ""
# body += p + prefix + e[2:] + ', '
# counter += 1
#
# return " TNimrod%s* = enum%s\n TNim%ss* = set[TNimrod%s]\n" \
# % (name, body.rstrip(", "), name, name)
#
#enums = eval(file("data/ast.yml").read())
#cog.out("type\n")
#i = 0
#for key, val in enums.iteritems():
# if key.endswith("Flag"): continue
# cog.out(toEnum(key, val, ["nnk", "nty", "nsk"][i]))
# i += 1
#]]]
type
TNimrodNodeKind* = enum
nnkNone, nnkEmpty, nnkIdent, nnkSym,
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit,
nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit,
nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall,
nnkCommand, nnkCall, nnkGenericCall, nnkExplicitTypeListCall,
nnkExprEqExpr, nnkExprColonExpr, nnkIdentDefs, nnkInfix,
nnkPrefix, nnkPostfix, nnkPar, nnkCurly,
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
nnkElifExpr, nnkElseExpr, nnkLambda, nnkAccQuoted,
nnkHeaderQuoted, nnkTableConstr, nnkQualified, nnkHiddenStdConv,
nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast,
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkAsgn,
nnkDefaultTypeParam, nnkGenericParams, nnkFormalParams, nnkOfInherit,
nnkModule, nnkProcDef, nnkConverterDef, nnkMacroDef,
nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch,
nnkExceptBranch, nnkElse, nnkMacroStmt, nnkAsmStmt,
nnkPragma, nnkIfStmt, nnkWhenStmt, nnkForStmt,
nnkWhileStmt, nnkCaseStmt, nnkVarSection, nnkConstSection,
nnkConstDef, nnkTypeSection, nnkTypeDef, nnkYieldStmt,
nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt,
nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkDiscardStmt,
nnkStmtList, nnkImportStmt, nnkFromStmt, nnkImportAs,
nnkIncludeStmt, nnkAccessStmt, nnkCommentStmt, nnkStmtListExpr,
nnkBlockExpr, nnkVm, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkProcTy,
nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
TNimNodeKinds* = set[TNimrodNodeKind]
TNimrodTypeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmptySet,
ntyArrayConstr, ntyNil, ntyGeneric, ntyGenericInst,
ntyGenericParam, ntyEnum, ntyAnyEnum, ntyArray,
ntyObject, ntyTuple, ntySet, ntyRange,
ntyPtr, ntyRef, ntyVar, ntySequence,
ntyProc, ntyPointer, ntyOpenArray, ntyString,
ntyCString, ntyForward, ntyInt, ntyInt8,
ntyInt16, ntyInt32, ntyInt64, ntyFloat,
ntyFloat32, ntyFloat64, ntyFloat128
TNimTypeKinds* = set[TNimrodTypeKind]
TNimrodSymKind* = enum
nskUnknownSym, nskConditional, nskDynLib, nskParam,
nskTypeParam, nskTemp, nskType, nskConst,
nskVar, nskProc, nskIterator, nskConverter,
nskMacro, nskTemplate, nskField, nskEnumField,
nskForVar, nskModule, nskLabel
TNimSymKinds* = set[TNimrodSymKind]
#[[[end]]]
type
TNimrodNode {.final.} = object # hidden
TNimrodSymbol {.final.} = object # hidden
TNimrodType {.final.} = object # hidden
PNimrodType* {.compilerproc.} = ref TNimrodType
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
PNimrodNode* {.compilerproc.} = ref TNimrodNode
expr* = PNimrodNode
stmt* = PNimrodNode
# Nodes should be reference counted to make the `copy` operation very fast!
# However, this is difficult to achieve: modify(n[0][1]) should propagate to
# its father. How to do this without back references?
proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
proc `[]=`* (n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
## provide access to `n`'s children
type
TNimrodIdent = object of TObject
converter StrToIdent*(s: string): TNimrodIdent {.magic: "StrToIdent".}
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent".}
proc len*(n: PNimrodNode): int {.magic: "NLen".}
## returns the number of children that a node has
proc add*(father, child: PNimrodNode) {.magic: "NAdd".}
proc add*(father: PNimrodNode, child: openArray[PNimrodNode]) {.magic: "NAddMultiple".}
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
proc typ*(n: PNimrodNode): PNimrodType {.magic: "NGetType".}
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".}
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
proc newNimNode*(kind: TNimrodNodeKind,
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
proc error*(msg: string) {.magic: "NError".}
proc warning*(msg: string) {.magic: "NWarning".}
proc hint*(msg: string) {.magic: "NHint".}
proc newStrLitNode*(s: string): PNimrodNode {.nodecl.} =
result = newNimNode(nnkStrLit)
result.strVal = s
proc newIntLitNode*(i: biggestInt): PNimrodNode {.nodecl.} =
result = newNimNode(nnkIntLit)
result.intVal = i
proc newIntLitNode*(f: biggestFloat): PNimrodNode {.nodecl.} =
result = newNimNode(nnkFloatLit)
result.floatVal = f
proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.nodecl.} =
result = newNimNode(nnkIdent)
result.ident = i
proc toStrLit*(n: PNimrodNode): PNimrodNode {.nodecl.} =
return newStrLitNode(repr(n))
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.nodecl.} =
if n.kind != k: error("macro expects a node of kind: " & repr(k))
proc expectMinLen*(n: PNimrodNode, min: int) {.nodecl.} =
if n.len < min: error("macro expects a node with " & $min & " children")
proc newCall*(theProc: TNimrodIdent,
args: openArray[PNimrodNode]): PNimrodNode {.nodecl.} =
## produces a new call node. `theProc` is the proc that is called with
## the arguments ``args[0..]``.
result = newNimNode(nnkCall)
result.add(newIdentNode(theProc))
result.add(args)

366
lib/parsecfg.nim Normal file
View File

@@ -0,0 +1,366 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## The ``parsecfg`` module implements a high performance configuration file
## parser. The configuration file's syntax is similar to the Windows ``.ini``
## format, but much more powerful, as it is not a line based parser. String
## literals, raw string literals and triple quote string literals are supported
## as in the Nimrod programming language.
## This is an example of how a configuration file may look like:
##
## .. include:: doc/mytest.cfg
## :literal:
## The file ``tests/tparscfg.nim`` demonstrates how to use the
## configuration file parser:
##
## .. code-block:: nimrod
## :file: tests/tparscfg.nim
import
hashes, strutils, lexbase
type
TCfgEventKind* = enum ## enumation of all events that may occur when parsing
cfgEof, ## end of file reached
cfgSectionStart, ## a ``[section]`` has been parsed
cfgKeyValuePair, ## a ``key=value`` pair has been detected
cfgOption, ## a ``--key=value`` command line option
cfgError ## an error ocurred during parsing
TCfgEvent* = object of TObject ## describes a parsing event
case kind*: TCfgEventKind ## the kind of the event
of cfgEof: dummy: string
of cfgSectionStart:
section*: string ## `section` contains the name of the
## parsed section start (syntax: ``[section]``)
of cfgKeyValuePair, cfgOption:
key*, value*: string ## contains the (key, value) pair if an option
## of the form ``--key: value`` or an ordinary
## ``key= value`` pair has been parsed.
## ``value==""`` if it was not specified in the
## configuration file.
of cfgError: ## the parser encountered an error: `msg`
msg*: string ## contains the error message. No exceptions
## are thrown if a parse error occurs.
TTokKind = enum
tkInvalid, tkEof,
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
TToken{.final.} = object # a token
kind: TTokKind # the type of the token
literal: string # the parsed (string) literal
TParserState = enum
startState, commaState
TCfgParser* = object of TBaseLexer ## the parser object.
tok: TToken
state: TParserState
filename: string
proc Open*(c: var TCfgParser, filename: string): bool
## initializes the parser, open the file for reading and returns true if
## successful (the file has been found).
proc OpenFromBuffer*(c: var TCfgParser, buf: string)
## initializes the parser with a buffer. This cannot fail.
proc close*(c: var TCfgParser)
## closes the parser `c`.
proc next*(c: var TCfgParser): TCfgEvent
## retrieves the first/next event. This controls the parser.
proc getColumn*(c: TCfgParser): int
## get the current column the parser has arrived at.
proc getLine*(c: TCfgParser): int
## get the current line the parser has arrived at.
proc getFilename*(c: TCfgParser): string
## get the filename of the file that the parser processes.
# implementation
const
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
proc rawGetTok(c: var TCfgParser, tok: var TToken)
proc open(c: var TCfgParser, filename: string): bool =
result = initBaseLexer(c, filename)
c.filename = filename
c.state = startState
c.tok.kind = tkInvalid
c.tok.literal = ""
if result: rawGetTok(c, c.tok)
proc openFromBuffer(c: var TCfgParser, buf: string) =
initBaseLexerFromBuffer(c, buf)
c.filename = "buffer"
c.state = startState
c.tok.kind = tkInvalid
c.tok.literal = ""
rawGetTok(c, c.tok)
proc close(c: var TCfgParser) =
deinitBaseLexer(c)
proc getColumn(c: TCfgParser): int =
result = getColNumber(c, c.bufPos)
proc getLine(c: TCfgParser): int =
result = c.linenumber
proc getFilename(c: TCfgParser): string =
result = c.filename
proc handleHexChar(c: var TCfgParser, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
of 'a'..'f':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
inc(c.bufpos)
of 'A'..'F':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else:
nil
proc handleDecChars(c: var TCfgParser, xi: var int) =
while c.buf[c.bufpos] in {'0'..'9'}:
xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
var xi: int
inc(c.bufpos) # skip '\'
case c.buf[c.bufpos]
of 'n', 'N':
tok.literal = tok.literal & nl
Inc(c.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, '\c')
Inc(c.bufpos)
of 'l', 'L':
add(tok.literal, '\L')
Inc(c.bufpos)
of 'f', 'F':
add(tok.literal, '\f')
inc(c.bufpos)
of 'e', 'E':
add(tok.literal, '\e')
Inc(c.bufpos)
of 'a', 'A':
add(tok.literal, '\a')
Inc(c.bufpos)
of 'b', 'B':
add(tok.literal, '\b')
Inc(c.bufpos)
of 'v', 'V':
add(tok.literal, '\v')
Inc(c.bufpos)
of 't', 'T':
add(tok.literal, '\t')
Inc(c.bufpos)
of '\'', '\"':
add(tok.literal, c.buf[c.bufpos])
Inc(c.bufpos)
of '\\':
add(tok.literal, '\\')
Inc(c.bufpos)
of 'x', 'X':
inc(c.bufpos)
xi = 0
handleHexChar(c, xi)
handleHexChar(c, xi)
add(tok.literal, Chr(xi))
of '0'..'9':
xi = 0
handleDecChars(c, xi)
if (xi <= 255): add(tok.literal, Chr(xi))
else: tok.kind = tkInvalid
else: tok.kind = tkInvalid
proc HandleCRLF(c: var TCfgParser, pos: int): int =
case c.buf[pos]
of '\c': result = lexbase.HandleCR(c, pos)
of '\L': result = lexbase.HandleLF(c, pos)
else: result = pos
proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
var
pos: int
ch: Char
buf: cstring
pos = c.bufPos + 1 # skip "
buf = c.buf # put `buf` in a register
tok.kind = tkSymbol
if (buf[pos] == '\"') and (buf[pos + 1] == '\"'):
# long string literal:
inc(pos, 2) # skip ""
# skip leading newline:
pos = HandleCRLF(c, pos)
while true:
case buf[pos]
of '\"':
if (buf[pos + 1] == '\"') and (buf[pos + 2] == '\"'): break
add(tok.literal, '\"')
Inc(pos)
of '\c', '\L':
pos = HandleCRLF(c, pos)
tok.literal = tok.literal & nl
of lexbase.EndOfFile:
tok.kind = tkInvalid
break
else:
add(tok.literal, buf[pos])
Inc(pos)
c.bufpos = pos +
3 # skip the three """
else:
# ordinary string literal
while true:
ch = buf[pos]
if ch == '\"':
inc(pos) # skip '"'
break
if ch in {'\c', '\L', lexbase.EndOfFile}:
tok.kind = tkInvalid
break
if (ch == '\\') and not rawMode:
c.bufPos = pos
getEscapedChar(c, tok)
pos = c.bufPos
else:
add(tok.literal, ch)
Inc(pos)
c.bufpos = pos
proc getSymbol(c: var TCfgParser, tok: var TToken) =
var
pos: int
buf: cstring
pos = c.bufpos
buf = c.buf
while true:
add(tok.literal, buf[pos])
Inc(pos)
if not (buf[pos] in SymChars): break
c.bufpos = pos
tok.kind = tkSymbol
proc skip(c: var TCfgParser) =
var
buf: cstring
pos: int
pos = c.bufpos
buf = c.buf
while true:
case buf[pos]
of ' ', '\t':
Inc(pos)
of '#', ';':
while not (buf[pos] in {'\c', '\L', lexbase.EndOfFile}): inc(pos)
of '\c', '\L':
pos = HandleCRLF(c, pos)
else:
break # EndOfFile also leaves the loop
c.bufpos = pos
proc rawGetTok(c: var TCfgParser, tok: var TToken) =
tok.kind = tkInvalid
setlen(tok.literal, 0)
skip(c)
case c.buf[c.bufpos]
of '=':
tok.kind = tkEquals
inc(c.bufpos)
of '-':
inc(c.bufPos)
if c.buf[c.bufPos] == '-': inc(c.bufPos)
tok.kind = tkDashDash
tok.literal = "--"
of ':':
tok.kind = tkColon
inc(c.bufpos)
tok.literal = ":"
of 'r', 'R':
if c.buf[c.bufPos + 1] == '\"':
Inc(c.bufPos)
getString(c, tok, true)
else:
getSymbol(c, tok)
of '[':
tok.kind = tkBracketLe
inc(c.bufpos)
tok.literal = "]"
of ']':
tok.kind = tkBracketRi
Inc(c.bufpos)
tok.literal = "]"
of '\"':
getString(c, tok, false)
of lexbase.EndOfFile:
tok.kind = tkEof
else: getSymbol(c, tok)
proc errorStr(c: TCfgParser, msg: string): string =
result = `%`("$1($2, $3) Error: $4",
[c.filename, toString(getLine(c)), toString(getColumn(c)), msg])
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
if c.tok.kind == tkSymbol:
result.kind = kind
result.key = c.tok.literal
result.value = ""
rawGetTok(c, c.tok)
if c.tok.kind in {tkEquals, tkColon}:
rawGetTok(c, c.tok)
if c.tok.kind == tkSymbol:
result.value = c.tok.literal
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
proc next(c: var TCfgParser): TCfgEvent =
case c.tok.kind
of tkEof:
result.kind = cfgEof
of tkDashDash:
rawGetTok(c, c.tok)
result = getKeyValPair(c, cfgOption)
of tkSymbol:
result = getKeyValPair(c, cfgKeyValuePair)
of tkBracketLe:
rawGetTok(c, c.tok)
if c.tok.kind == tkSymbol:
result.kind = cfgSectionStart
result.section = c.tok.literal
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
if c.tok.kind == tkBracketRi:
rawGetTok(c, c.tok)
else:
result.kind = cfgError
result.msg = errorStr(c, "\']\' expected, but found: " & c.tok.literal)
of tkInvalid, tkEquals, tkColon, tkBracketRi:
result.kind = cfgError
result.msg = errorStr(c, "invalid token: " & c.tok.literal)
rawGetTok(c, c.tok)

154
lib/parseopt.nim Normal file
View File

@@ -0,0 +1,154 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides the standard Nimrod command line parser.
## It supports one convenience iterator over all command line options and some
## lower-level features.
{.push debugger: off.}
import
os, strutils
type
TCmdLineKind* = enum ## the detected command line token
cmdEnd, ## end of command line reached
cmdArgument, ## argument detected
cmdLongoption, ## a long option ``--option`` detected
cmdShortOption ## a short option ``-c`` detected
TOptParser* =
object of TObject ## this object implements the command line parser
cmd: string
pos: int
inShortState: bool
kind*: TCmdLineKind ## the dected command line token
key*, val*: string ## key and value pair; ``key`` is the option
## or the argument, ``value`` is not "" if
## the option was given a value
proc init*(cmdline: string = ""): TOptParser
## inits the option parser. If ``cmdline == ""``, the real command line
## (as provided by the ``OS`` module) is taken.
proc next*(p: var TOptParser)
## parses the first or next option; ``p.kind`` describes what token has been
## parsed. ``p.key`` and ``p.val`` are set accordingly.
proc getRestOfCommandLine*(p: TOptParser): string
## retrieves the rest of the command line that has not been parsed yet.
# implementation
proc init(cmdline: string = ""): TOptParser =
result.pos = strStart
result.inShortState = false
if cmdline != "":
result.cmd = cmdline
else:
result.cmd = ""
for i in countup(1, ParamCount()):
result.cmd = result.cmd & quoteIfSpaceExists(paramStr(i)) & ' '
result.kind = cmdEnd
result.key = ""
result.val = ""
proc parseWord(s: string, i: int, w: var string,
delim: TCharSet = {'\x09', ' ', '\0'}): int =
result = i
if s[result] == '\"':
inc(result)
while not (s[result] in {'\0', '\"'}):
add(w, s[result])
inc(result)
if s[result] == '\"': inc(result)
else:
while not (s[result] in delim):
add(w, s[result])
inc(result)
proc handleShortOption(p: var TOptParser) =
var i: int
i = p.pos
p.kind = cmdShortOption
add(p.key, p.cmd[i])
inc(i)
p.inShortState = true
while p.cmd[i] in {'\x09', ' '}:
inc(i)
p.inShortState = false
if p.cmd[i] in {':', '='}:
inc(i)
p.inShortState = false
while p.cmd[i] in {'\x09', ' '}: inc(i)
i = parseWord(p.cmd, i, p.val)
if p.cmd[i] == '\0': p.inShortState = false
p.pos = i
proc next(p: var TOptParser) =
var i: int
i = p.pos
while p.cmd[i] in {'\x09', ' '}: inc(i)
p.pos = i
setlen(p.key, 0)
setlen(p.val, 0)
if p.inShortState:
handleShortOption(p)
return
case p.cmd[i]
of '\0':
p.kind = cmdEnd
of '-':
inc(i)
if p.cmd[i] == '-':
p.kind = cmdLongOption
inc(i)
i = parseWord(p.cmd, i, p.key, {'\0', ' ', '\x09', ':', '='})
while p.cmd[i] in {'\x09', ' '}: inc(i)
if p.cmd[i] in {':', '='}:
inc(i)
while p.cmd[i] in {'\x09', ' '}: inc(i)
p.pos = parseWord(p.cmd, i, p.val)
else:
p.pos = i
else:
p.pos = i
handleShortOption(p)
else:
p.kind = cmdArgument
p.pos = parseWord(p.cmd, i, p.key)
proc getRestOfCommandLine(p: TOptParser): string =
result = strip(copy(p.cmd, p.pos + strStart, len(p.cmd) - 1))
iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
##this is an convenience iterator for iterating over the command line.
##This uses the TOptParser object. Example:
##
## .. code-block:: nimrod
## var
## filename = ""
## for kind, key, val in getopt():
## case kind
## of cmdArgument:
## filename = key
## of cmdLongOption, cmdShortOption:
## case key
## of "help", "h": writeHelp()
## of "version", "v": writeVersion()
## of cmdEnd: assert(false) # cannot happen
## if filename == "":
## # no filename has been given, so we show the help:
## writeHelp()
var p = init()
while true:
next(p)
if p.kind == cmdEnd: break
yield (p.kind, p.key, p.val)
{.pop.}

19
lib/smallalc.nim Normal file
View File

@@ -0,0 +1,19 @@
# Handle small allocations efficiently
# We allocate and manage memory by pages. All objects within a page belong to
# the same type. Thus, we safe the type field. Minimum requested block is
# 8 bytes. Alignment is 8 bytes.
type
TChunk {.pure.} = object
kind: TChunkKind
prev, next: ptr TChunk
TSmallChunk = object of TChunk # all objects of the same size
typ: PNimType
free: int
data: array [0.., int]
proc allocSmall(typ: PNimType): pointer =

210
lib/strtabs.nim Normal file
View File

@@ -0,0 +1,210 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## The ``strtabs`` module implements an efficient hash table that is a mapping
## from strings to strings. Supports a case-sensitive, case-insensitive and
## style-insensitive mode. An efficient string substitution operator ``%``
## for the string table is also provided.
import
os, hashes, strutils
type
TStringTableMode* = enum # describes the tables operation mode
modeCaseSensitive, # the table is case sensitive
modeCaseInsensitive, # the table is case insensitive
modeStyleInsensitive # the table is style insensitive
TKeyValuePair = tuple[key, val: string]
TKeyValuePairSeq = seq[TKeyValuePair]
TStringTable* = object of TObject
counter: int
data: TKeyValuePairSeq
mode: TStringTableMode
PStringTable* = ref TStringTable ## use this type to declare string tables
proc newStringTable*(keyValuePairs: openarray[string],
mode: TStringTableMode = modeCaseSensitive): PStringTable
## creates a new string table with given key value pairs.
## Example::
## var mytab = newStringTable("key1", "val1", "key2", "val2",
## modeCaseInsensitive)
proc newStringTable*(mode: TStringTableMode = modeCaseSensitive): PStringTable
## creates a new string table that is empty.
proc `[]=`*(t: PStringTable, key, val: string)
## puts a (key, value)-pair into `t`.
proc `[]`*(t: PStringTable, key: string): string
## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
proc hasKey*(t: PStringTable, key: string): bool
## returns true iff `key` is in the table `t`.
proc len*(t: PStringTable): int =
## returns the number of keys in `t`.
result = t.counter
iterator pairs*(t: PStringTable): tuple[key, value: string] =
## iterates over any (key, value) pair in the table `t`.
for h in 0..high(t.data):
if not isNil(t.data[h].key):
yield (t.data[h].key, t.data[h].val)
type
TFormatFlag* = enum # flags for the `%` operator
useEnvironment, # use environment variable if the ``$key``
# is not found in the table
useEmpty, # use the empty string as a default, thus it
# won't throw an exception if ``$key`` is not
# in the table
useKey # do not replace ``$key`` if it is not found
# in the table (or in the environment)
proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string
## The `%` operator for string tables.
# implementation
const
growthFactor = 2
startSize = 64
proc newStringTable(mode: TStringTableMode = modeCaseSensitive): PStringTable =
new(result)
result.mode = mode
result.counter = 0
result.data = []
setlen(result.data, startSize) # XXX
proc newStringTable(keyValuePairs: openarray[string],
mode: TStringTableMode = modeCaseSensitive): PStringTable =
result = newStringTable(mode)
var i = 0
while i < high(keyValuePairs):
result[keyValuePairs[i]] = keyValuePairs[i + 1]
inc(i, 2)
proc myhash(t: PStringTable, key: string): THash =
case t.mode
of modeCaseSensitive: result = hashes.hash(key)
of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
of modeStyleInsensitive: result = hashes.hashIgnoreStyle(key)
proc myCmp(t: PStringTable, a, b: string): bool =
case t.mode
of modeCaseSensitive: result = cmp(a, b) == 0
of modeCaseInsensitive: result = cmpIgnoreCase(a, b) == 0
of modeStyleInsensitive: result = cmpIgnoreStyle(a, b) == 0
proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
const
EmptySeq = []
proc nextTry(h, maxHash: THash): THash =
result = ((5 * h) + 1) and maxHash # For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc RawGet(t: PStringTable, key: string): int =
var h: THash
h = myhash(t, key) and high(t.data) # start with real hash value
while not isNil(t.data[h].key):
if mycmp(t, t.data[h].key, key):
return h
h = nextTry(h, high(t.data))
result = - 1
proc `[]`(t: PStringTable, key: string): string =
var index: int
index = RawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = ""
proc hasKey(t: PStringTable, key: string): bool =
result = rawGet(t, key) >= 0
proc RawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) =
var h: THash
h = myhash(t, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
proc Enlarge(t: PStringTable) =
var n: TKeyValuePairSeq
n = emptySeq
setlen(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if not isNil(t.data[i].key): RawInsert(t, n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc `[]=`(t: PStringTable, key, val: string) =
var index = RawGet(t, key)
if index >= 0:
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter): Enlarge(t)
RawInsert(t, t.data, key, val)
inc(t.counter)
proc RaiseFormatException(s: string) =
var e: ref EInvalidValue
new(e)
e.msg = "format string: key not found: " & s
raise e
proc getValue(t: PStringTable, flags: set[TFormatFlag], key: string): string =
if hasKey(t, key): return t[key]
if useEnvironment in flags: result = os.getEnv(key)
else: result = ""
if (result == ""):
if useKey in flags: result = '$' & key
elif not (useEmpty in flags): raiseFormatException(key)
proc `%`(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string =
const
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
var
i, j: int
key: string
result = ""
i = strStart
while i <= len(f) + strStart - 1:
if f[i] == '$':
case f[i + 1]
of '$':
add(result, '$')
inc(i, 2)
of '{':
j = i + 1
while (j <= len(f) + strStart - 1) and (f[j] != '}'): inc(j)
key = copy(f, i + 2, j - 1)
result = result & getValue(t, flags, key)
i = j + 1
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_':
j = i + 1
while (j <= len(f) + strStart - 1) and (f[j] in PatternChars): inc(j)
key = copy(f, i+1, j - 1)
result = result & getValue(t, flags, key)
i = j
else:
add(result, f[i])
inc(i)
else:
add(result, f[i])
inc(i)

72
lib/tinalloc.nim Normal file
View File

@@ -0,0 +1,72 @@
# Memory handling for small objects
const
minRequestSize = 2 * sizeof(pointer) # minimal block is 16 bytes
pageSize = 1024 * sizeof(int)
pageBits = pageSize div minRequestSize
pageMask = pageSize-1
bitarraySize = pageBits div (sizeof(int)*8)
dataSize = pageSize - (bitarraySize+6) * sizeof(pointer)
type
TMinRequest {.final.} = object
next, prev: ptr TMinRequest # stores next free bit
TChunk {.pure.} = object # a chunk manages at least a page
size: int # lowest bit signals if it is a small chunk (0) or
# a big chunk (1)
typ: PNimType
next, prev: ptr TChunk
nextOfSameType: ptr TChunk
TSmallChunk = object of TChunk ## manages pageSize bytes for a type and a
## fixed size
free: int ## index of first free bit
bits: array[0..bitarraySize-1, int]
data: array[0..dataSize div minRequestSize - 1, TMinRequest]
PSmallChunk = ptr TSmallChunk
assert(sizeof(TSmallChunk) == pageSize)
proc getNewChunk(size: int, typ: PNimType): PSmallChunk =
result = cast[PSmallChunk](getPages(1))
result.size = PageSize
result.typ = typ
result.next = chunkHead
result.prev = nil
chunkHead.prev = result
chunkHead = result.next
result.nextOfSameType = cast[PSmallChunk](typ.chunk)
typ.chunk = result
result.free = addr(result.data[0])
result.data[0].next = addr(result.data[1])
result.data[0].prev = nil
result.data[high(result.data)].next = nil
result.data[high(result.data)].prev = addr(result.data[high(result.data)-1])
for i in 1..high(result.data)-1:
result.data[i].next = addr(result.data[i+1])
result.data[i].prev = addr(result.data[i-1])
proc newSmallObj(size: int, typ: PNimType): pointer =
var chunk = cast[PSmallChunk](typ.chunk)
if chunk == nil or chunk.free <= 0:
if chunk.free < 0: GC_collect()
chunk = getNewChunk(size, typ)
chunk.nextOfSameType = typ.chunk
typ.chunk = chunk
var idx = chunk.free
setBit(chunk.bits[idx /% bitarraySize], idx %% bitarraySize)
result = cast[pointer](cast[TAddress](addr(chunk.data)) +
minRequestSize * idx)
var res = cast[PMinRequest](result)
chunk.free = res.next
res.next
proc freeObj(obj: pointer) =
var chunk = cast[PChunk](cast[TAddress(obj) and not pageMask)
if size and 1 == 0: # small chunk
var idx = (cast[TAddress](obj) shr pageShift) div minRequestSize
resetBit(chunk.bits[idx /% bitarraySize], idx %% bitarraySize)

1107
lib/wz_jsgraphics.js Normal file

File diff suppressed because it is too large Load Diff

21
tests/ecmas.html Normal file
View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- This has been written by hand. (c) 2008 Andreas Rumpf -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Nimrod ECMAScript Generator Test</title>
<style type="text/css">
span.DecNumber {color: blue}
</style>
<script src="rod_gen/ecmas.js" type="text/javascript"></script>
</head>
<body onload="OnLoad()">
<form name="form1" action="ecmas.html">
<input type="text" name="input" size="3" />
<input type="button" value="Calculate square" onclick="OnButtonClick()" />
</form>
</body>
</html>

16
tests/ecmas.nim Normal file
View File

@@ -0,0 +1,16 @@
# This file tests the ECMAScript generator
import
dom, strutils
# We need to declare the used elements here. This is annoying but
# prevents any kind of typo:
var
inputElement {.importc: "document.form1.input", nodecl.}: ref TElement
proc OnButtonClick() {.exportc.} =
var x: int = parseInt($inputElement.value)
echo($(x * x))
proc OnLoad() {.exportc.} =
echo("Welcome! Please take your time to fill in this formular!")

172
tests/gcbench.nim Normal file
View File

@@ -0,0 +1,172 @@
# This is adapted from a benchmark written by John Ellis and Pete Kovac
# of Post Communications.
# It was modified by Hans Boehm of Silicon Graphics.
#
# This is no substitute for real applications. No actual application
# is likely to behave in exactly this way. However, this benchmark was
# designed to be more representative of real applications than other
# Java GC benchmarks of which we are aware.
# It attempts to model those properties of allocation requests that
# are important to current GC techniques.
# It is designed to be used either to obtain a single overall performance
# number, or to give a more detailed estimate of how collector
# performance varies with object lifetimes. It prints the time
# required to allocate and collect balanced binary trees of various
# sizes. Smaller trees result in shorter object lifetimes. Each cycle
# allocates roughly the same amount of memory.
# Two data structures are kept around during the entire process, so
# that the measured performance is representative of applications
# that maintain some live in-memory data. One of these is a tree
# containing many pointers. The other is a large array containing
# double precision floating point numbers. Both should be of comparable
# size.
#
# The results are only really meaningful together with a specification
# of how much memory was used. It is possible to trade memory for
# better time performance. This benchmark should be run in a 32 MB
# heap, though we don't currently know how to enforce that uniformly.
#
# Unlike the original Ellis and Kovac benchmark, we do not attempt
# measure pause times. This facility should eventually be added back
# in. There are several reasons for omitting it for now. The original
# implementation depended on assumptions about the thread scheduler
# that don't hold uniformly. The results really measure both the
# scheduler and GC. Pause time measurements tend to not fit well with
# current benchmark suites. As far as we know, none of the current
# commercial Java implementations seriously attempt to minimize GC pause
# times.
#
# Known deficiencies:
# - No way to check on memory use
# - No cyclic data structures
# - No attempt to measure variation with object size
# - Results are sensitive to locking cost, but we dont
# check for proper locking
#
import
strutils, times
type
PNode = ref TNode
TNode {.final.} = object
left, right: PNode
i, j: int
proc newNode(l, r: PNode): PNode =
new(result)
result.left = l
result.right = r
const
kStretchTreeDepth = 18 # about 16Mb
kLongLivedTreeDepth = 16 # about 4Mb
kArraySize = 500000 # about 4Mb
kMinTreeDepth = 4
kMaxTreeDepth = 16
# Nodes used by a tree of a given size
proc TreeSize(i: int): int = return ((1 shl (i + 1)) - 1)
# Number of iterations to use for a given tree depth
proc NumIters(i: int): int =
return 2 * TreeSize(kStretchTreeDepth) div TreeSize(i)
# Build tree top down, assigning to older objects.
proc Populate(iDepth: int, thisNode: PNode) =
if iDepth <= 0:
return
else:
new(thisNode.left)
new(thisNode.right)
Populate(iDepth-1, thisNode.left)
Populate(iDepth-1, thisNode.right)
# Build tree bottom-up
proc MakeTree(iDepth: int): PNode =
if iDepth <= 0:
new(result)
else:
return newNode(MakeTree(iDepth-1),
MakeTree(iDepth-1))
proc PrintDiagnostics() =
var
FreeMemory = getFreeMem()
TotalMemory = getTotalMem()
echo("Total memory available: " & $TotalMemory & " bytes")
echo("Free memory: " & $FreeMemory & " bytes")
proc TimeConstruction(depth: int) =
var
root, tempTree: PNode
t: int
iNumIters: int
iNumIters = NumIters(depth)
echo("Creating " & $iNumIters & " trees of depth " & $depth)
t = getStartMilsecs()
for i in 0..iNumIters-1:
new(tempTree)
Populate(depth, tempTree)
tempTree = nil
echo("\tTop down construction took " &
$(getStartMilsecs() - t) & "msecs")
t = getStartMilsecs()
for i in 0..iNumIters-1:
tempTree = MakeTree(depth)
tempTree = nil
echo("\tBottom up construction took " &
$(getStartMilsecs() - t) & "msecs")
type
tMyArray = seq[float]
proc main() =
var
root, longLivedTree, tempTree: PNode
t: int
myarray: tMyArray
echo("Garbage Collector Test")
echo(" Stretching memory with a binary tree of depth " &
$kStretchTreeDepth)
PrintDiagnostics()
t = getStartMilsecs()
# Stretch the memory space quickly
tempTree = MakeTree(kStretchTreeDepth)
tempTree = nil
# Create a long lived object
echo(" Creating a long-lived binary tree of depth " &
$kLongLivedTreeDepth)
new(longLivedTree)
Populate(kLongLivedTreeDepth, longLivedTree)
# Create long-lived array, filling half of it
echo(" Creating a long-lived array of " & $kArraySize & " doubles")
myarray = []
setlength(myarray, kArraySize)
for i in 0..kArraySize div 2 -1:
myarray[i] = 1.0 / toFloat(i)
PrintDiagnostics()
var d = kMinTreeDepth
while d <= kMaxTreeDepth:
TimeConstruction(d)
inc(d, 2)
if longLivedTree == nil or myarray[1000] != 1.0/1000.0:
echo("Failed")
# fake reference to LongLivedTree
# and array to keep them from being optimized away
var elapsed = getStartMilsecs() - t
PrintDiagnostics()
echo("Completed in " & $elapsed & "ms.")
main()

34
tests/hallo.nim Normal file
View File

@@ -0,0 +1,34 @@
# Hallo world program
echo("Hi! What's your name?")
var name = readLine(stdin)
if name == "Andreas":
echo("What a nice name!")
elif name == "":
echo("Don't you have a name?")
else:
echo("Your name is not Andreas...")
for i in 0..name.len-1:
if name[i] == 'm':
echo("hey, there is an *m* in your name!")
echo("Please give your password: (12345)")
var pw = readLine(stdin)
while pw != "12345":
echo("Wrong password! Next try: ")
pw = readLine(stdin)
echo("""Login complete!
What do you want to do?
delete-everything
restart-computer
go-for-a-walk""")
case readline(stdin)
of "delete-everything", "restart-computer":
echo("permission denied")
of "go-for-a-walk": echo("please yourself")
else: echo("unknown command")

6
tests/rectest.nim Normal file
View File

@@ -0,0 +1,6 @@
# Test the error message
proc main() =
main()
main()

25
tests/tparscfg.nim Normal file
View File

@@ -0,0 +1,25 @@
import
os, parsecfg, strutils
var
p: TCfgParser
if open(p, paramStr(1)):
while true:
var e = next(p)
case e.kind
of cfgEof:
echo("EOF!")
break
of cfgSectionStart: ## a ``[section]`` has been parsed
echo("new section: " & e.section)
of cfgKeyValuePair:
echo("key-value-pair: " & e.key & ": " & e.value)
of cfgOption:
echo("command: " & e.key & ": " & e.value)
of cfgError:
echo(e.msg)
close(p)
else:
echo("cannot open: " & paramStr(1))

27
tests/tparsopt.nim Normal file
View File

@@ -0,0 +1,27 @@
# Test the new parseopt module
import
parseopt
proc writeHelp() =
writeln(stdout, "Usage: tparsopt [options] filename [options]")
proc writeVersion() =
writeln(stdout, "Version: 1.0.0")
var
filename = ""
for kind, key, val in getopt():
case kind
of cmdArgument:
filename = key
of cmdLongOption, cmdShortOption:
case key
of "help", "h": writeHelp()
of "version", "v": writeVersion()
else:
writeln(stdout, "Unknown command line option: ", key, ": ", val)
of cmdEnd: assert(false) # cannot happen
if filename == "":
# no filename has been given, so we show the help:
writeHelp()

319
tests/tradix.nim Normal file
View File

@@ -0,0 +1,319 @@
# implements and tests an efficient radix tree
## another method to store an efficient array of pointers:
## We use a radix tree with node compression.
## There are two node kinds:
const bitsPerUnit = 8*sizeof(int)
type
TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear
PRadixNode = ptr TRadixNode
TRadixNode {.pure.} = object
kind: TRadixNodeKind
TRadixNodeLinear = object of TRadixNode
len: byte
keys: array [0..31, byte]
vals: array [0..31, PRadixNode]
TRadixNodeFull = object of TRadixNode
b: array [0..255, PRadixNode]
TRadixNodeLeafBits = object of TRadixNode
b: array [0..7, int]
TRadixNodeLeafLinear = object of TRadixNode
len: byte
keys: array [0..31, byte]
var
root: PRadixNode
proc searchInner(r: PRadixNode, a: int): PRadixNode =
case r.kind
of rnLinear:
var x = cast[ptr TRadixNodeLinear](r)
for i in 0..x.len-1:
if ze(x.keys[i]) == a: return x.vals[i]
of rnFull:
var x = cast[ptr TRadixNodeFull](r)
return x.b[a]
else: assert(false)
proc testBit(w, i: int): bool {.inline.} =
result = (w and (1 shl (i %% BitsPerUnit))) != 0
proc setBit(w: var int, i: int) {.inline.} =
w = w or (1 shl (i %% bitsPerUnit))
proc resetBit(w: var int, i: int) {.inline.} =
w = w and not (1 shl (i %% bitsPerUnit))
proc testOrSetBit(w: var int, i: int): bool {.inline.} =
var x = (1 shl (i %% bitsPerUnit))
if (w and x) != 0: return true
w = w or x
proc searchLeaf(r: PRadixNode, a: int): bool =
case r.kind
of rnLeafBits:
var x = cast[ptr TRadixNodeLeafBits](r)
return testBit(x.b[a /% BitsPerUnit], a)
of rnLeafLinear:
var x = cast[ptr TRadixNodeLeafLinear](r)
for i in 0..x.len-1:
if ze(x.keys[i]) == a: return true
else: assert(false)
proc exclLeaf(r: PRadixNode, a: int) =
case r.kind
of rnLeafBits:
var x = cast[ptr TRadixNodeLeafBits](r)
resetBit(x.b[a /% BitsPerUnit], a)
of rnLeafLinear:
var x = cast[ptr TRadixNodeLeafLinear](r)
var L = ze(x.len)
for i in 0..L-1:
if ze(x.keys[i]) == a:
x.keys[i] = x.keys[L-1]
dec(x.len)
return
else: assert(false)
proc in_Operator*(r: PRadixNode, a: TAddress): bool =
if r == nil: return false
var x = searchInner(r, a shr 24 and 0xff)
if x == nil: return false
x = searchInner(x, a shr 16 and 0xff)
if x == nil: return false
x = searchInner(x, a shr 8 and 0xff)
if x == nil: return false
return searchLeaf(x, a and 0xff)
proc excl*(r: PRadixNode, a: TAddress): bool =
if r == nil: return false
var x = searchInner(r, a shr 24 and 0xff)
if x == nil: return false
x = searchInner(x, a shr 16 and 0xff)
if x == nil: return false
x = searchInner(x, a shr 8 and 0xff)
if x == nil: return false
exclLeaf(x, a and 0xff)
proc addLeaf(r: var PRadixNode, a: int): bool =
if r == nil:
# a linear node:
var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
x.kind = rnLeafLinear
x.len = 1
x.keys[0] = toU8(a)
r = x
return false # not already in set
case r.kind
of rnLeafBits:
var x = cast[ptr TRadixNodeLeafBits](r)
return testOrSetBit(x.b[a /% BitsPerUnit], a)
of rnLeafLinear:
var x = cast[ptr TRadixNodeLeafLinear](r)
var L = ze(x.len)
for i in 0..L-1:
if ze(x.keys[i]) == a: return true
if L <= high(x.keys):
x.keys[L] = toU8(a)
inc(x.len)
else:
# transform into a full node:
var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits)))
y.kind = rnLeafBits
for i in 0..x.len-1:
var u = ze(x.keys[i])
setBit(y.b[u /% BitsPerUnit], u)
setBit(y.b[a /% BitsPerUnit], a)
dealloc(r)
r = y
else: assert(false)
proc addInner(r: var PRadixNode, a: int, d: int): bool =
if d == 0:
return addLeaf(r, a and 0xff)
var k = a shr d and 0xff
if r == nil:
# a linear node:
var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
x.kind = rnLinear
x.len = 1
x.keys[0] = toU8(k)
r = x
return addInner(x.vals[0], a, d-8)
case r.kind
of rnLinear:
var x = cast[ptr TRadixNodeLinear](r)
var L = ze(x.len)
for i in 0..L-1:
if ze(x.keys[i]) == k: # already exists
return addInner(x.vals[i], a, d-8)
if L <= high(x.keys):
x.keys[L] = toU8(k)
inc(x.len)
return addInner(x.vals[L], a, d-8)
else:
# transform into a full node:
var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull)))
y.kind = rnFull
for i in 0..L-1: y.b[ze(x.keys[i])] = x.vals[i]
dealloc(r)
r = y
return addInner(y.b[k], a, d-8)
of rnFull:
var x = cast[ptr TRadixNodeFull](r)
return addInner(x.b[k], a, d-8)
else: assert(false)
proc incl*(r: var PRadixNode, a: TAddress) {.inline.} =
discard addInner(r, a, 24)
proc testOrIncl*(r: var PRadixNode, a: TAddress): bool {.inline.} =
return addInner(r, a, 24)
iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] =
if r != nil:
case r.kind
of rnFull:
var r = cast[ptr TRadixNodeFull](r)
for i in 0..high(r.b):
if r.b[i] != nil:
yield (i, r.b[i])
of rnLinear:
var r = cast[ptr TRadixNodeLinear](r)
for i in 0..ze(r.len)-1:
yield (ze(r.keys[i]), r.vals[i])
else: assert(false)
iterator leafElements(r: PRadixNode): int =
if r != nil:
case r.kind
of rnLeafBits:
var r = cast[ptr TRadixNodeLeafBits](r)
# iterate over any bit:
for i in 0..high(r.b):
if r.b[i] != 0: # test all bits for zero
for j in 0..BitsPerUnit-1:
if testBit(r.b[i], j):
yield i*BitsPerUnit+j
of rnLeafLinear:
var r = cast[ptr TRadixNodeLeafLinear](r)
for i in 0..ze(r.len)-1:
yield ze(r.keys[i])
else: assert(false)
iterator elements*(r: PRadixNode): TAddress {.inline.} =
for p1, n1 in innerElements(r):
for p2, n2 in innerElements(n1):
for p3, n3 in innerElements(n2):
for p4 in leafElements(n3):
yield p1 shl 24 or p2 shl 16 or p3 shl 8 or p4
proc main() =
const
numbers = [128, 1, 2, 3, 4, 255, 17, -8, 45, 19_000]
var
r: PRadixNode = nil
for x in items(numbers):
echo testOrIncl(r, x)
for x in elements(r): echo(x)
main()
when false:
proc traverse(r: PRadixNode, prefix: int, d: int) =
if r == nil: return
case r.kind
of rnLeafBits:
assert(d == 0)
var x = cast[ptr TRadixNodeLeafBits](r)
# iterate over any bit:
for i in 0..high(x.b):
if x.b[i] != 0: # test all bits for zero
for j in 0..BitsPerUnit-1:
if testBit(x.b[i], j):
visit(prefix or i*BitsPerUnit+j)
of rnLeafLinear:
assert(d == 0)
var x = cast[ptr TRadixNodeLeafLinear](r)
for i in 0..ze(x.len)-1:
visit(prefix or ze(x.keys[i]))
of rnFull:
var x = cast[ptr TRadixNodeFull](r)
for i in 0..high(r.b):
if r.b[i] != nil:
traverse(r.b[i], prefix or (i shl d), d-8)
of rnLinear:
var x = cast[ptr TRadixNodeLinear](r)
for i in 0..ze(x.len)-1:
traverse(x.vals[i], prefix or (ze(x.keys[i]) shl d), d-8)
type
TRadixIter {.final.} = object
r: PRadixNode
p: int
x: int
proc init(i: var TRadixIter, r: PRadixNode) =
i.r = r
i.x = 0
i.p = 0
proc nextr(i: var TRadixIter): PRadixNode =
if i.r == nil: return nil
case i.r.kind
of rnFull:
var r = cast[ptr TRadixNodeFull](i.r)
while i.x <= high(r.b):
if r.b[i.x] != nil:
i.p = i.x
return r.b[i.x]
inc(i.x)
of rnLinear:
var r = cast[ptr TRadixNodeLinear](i.r)
if i.x < ze(r.len):
i.p = ze(r.keys[i.x])
result = r.vals[i.x]
inc(i.x)
else: assert(false)
proc nexti(i: var TRadixIter): int =
result = -1
case i.r.kind
of rnLeafBits:
var r = cast[ptr TRadixNodeLeafBits](i.r)
# iterate over any bit:
for i in 0..high(r.b):
if x.b[i] != 0: # test all bits for zero
for j in 0..BitsPerUnit-1:
if testBit(x.b[i], j):
visit(prefix or i*BitsPerUnit+j)
of rnLeafLinear:
var r = cast[ptr TRadixNodeLeafLinear](i.r)
if i.x < ze(r.len):
result = ze(r.keys[i.x])
inc(i.x)
iterator elements(r: PRadixNode): TAddress {.inline.} =
var
a, b, c, d: TRadixIter
init(a, r)
while true:
var x = nextr(a)
if x != nil:
init(b, x)
while true:
var y = nextr(b)
if y != nil:
init(c, y)
while true:
var z = nextr(c)
if z != nil:
init(d, z)
while true:
var q = nexti(d)
if q != -1:
yield a.p shl 24 or b.p shl 16 or c.p shl 8 or q

76
tests/tstrset.nim Normal file
View File

@@ -0,0 +1,76 @@
# test a simple yet highly efficient set of strings
type
TRadixNodeKind = enum rnLinear, rnFull, rnLeaf
PRadixNode = ptr TRadixNode
TRadixNode = object
kind: TRadixNodeKind
TRadixNodeLinear = object of TRadixNode
len: byte
keys: array [0..31, char]
vals: array [0..31, PRadixNode]
TRadixNodeFull = object of TRadixNode
b: array [char, PRadixNode]
TRadixNodeLeaf = object of TRadixNode
s: string
PRadixNodeLinear = ref TRadixNodeLinear
PRadixNodeFull = ref TRadixNodeFull
PRadixNodeLeaf = ref TRadixNodeLeaf
proc search(r: PRadixNode, s: string): PRadixNode =
var r = r
var i = 0
while r != nil:
case r.kind
of rnLinear:
var x = PRadixNodeLinear(r)
for j in 0..x.len-1:
if x.keys[j] == s[i]:
if s[i] == '\0': return r
r = x.vals[j]
inc(i)
break
break # character not found
of rnFull:
var x = PRadixNodeFull(r)
var y = x.b[s[i]]
if s[i] == '\0':
return if y != nil: r else: nil
r = y
inc(i)
of rnLeaf:
var x = PRadixNodeLeaf(r)
var j = 0
while true:
if x.s[j] != s[i]: return nil
if s[i] == '\0': return r
inc(j)
inc(i)
proc in_Operator*(r: PRadixNode, s: string): bool =
return search(r, s) != nil
proc testOrincl*(r: var PRadixNode, s: string): bool =
nil
proc incl*(r: var PRadixNode, s: string) = discard testOrIncl(r, s)
proc excl*(r: var PRadixNode, s: string) =
x = search(r, s)
if x == nil: return
case x.kind
of rnLeaf: PRadixNodeLeaf(x).s = ""
of rnFull: PRadixNodeFull(x).b['\0'] = nil
of rnLinear:
var x = PRadixNodeLinear(x)
for i in 0..x.len-1:
if x.keys[i] == '\0':
swap(x.keys[i], x.keys[x.len-1])
dec(x.len)
break
var
root: PRadixNode

12
tests/tstrtabs.nim Normal file
View File

@@ -0,0 +1,12 @@
import strtabs
var tab = newStringTable(["key1", "val1", "key2", "val2"],
modeStyleInsensitive)
for i in 0..80:
tab["key_" & $i] = "value" & $i
for key, val in pairs(tab):
writeln(stdout, key, ": ", val)
writeln(stdout, "length of table ", $tab.len)
writeln(stdout, `%`("$key1 = $key2; ${PATH}", tab, {useEnvironment}))

View File

@@ -1 +0,0 @@
.. include:: ../doc/docs.txt

View File

@@ -1 +0,0 @@
%(body)s

View File

@@ -1,19 +0,0 @@
"There are two major products that come out of Berkeley: LSD and UNIX.
We don't believe this to be a coincidence." -- Jeremy S. Anderson.
Here you can download the latest version of the Nimrod Compiler.
Please choose your platform:
* source for Linux (i386): `<download/nimrod_linux_i386_0.6.0.zip>`_
* source for Linux (amd64): `<download/nimrod_linux_amd64_0.6.0.zip>`_
* source for Linux (sparc, untested!): `<download/nimrod_linux_sparc_0.6.0.zip>`_
* source for Mac OS X (i386): `<download/nimrod_macosx_i386_0.6.0.zip>`_
* source for Mac OS X (amd64, untested!): `<download/nimrod_macosx_amd64_0.6.0.zip>`_
* source for Solaris (i386, untested!): `<download/nimrod_solaris_i386_0.6.0.zip>`_
* source for Solaris (amd64, untested!): `<download/nimrod_solaris_amd64_0.6.0.zip>`_
* source for Solaris (sparc, untested!): `<download/nimrod_solaris_sparc_0.6.0.zip>`_
* source for Windows (i386): `<download/nimrod_windows_i386_0.6.0.zip>`_
* source for Windows (amd64, untested!): `<download/nimrod_windows_amd64_0.6.0.zip>`_
* installer for Windows (i386): `<download/nimrod_windows_0.6.0.exe>`_
(includes LLVM and everything else you need)
.. include:: ../install.txt

View File

@@ -1,64 +0,0 @@
====
Home
====
"The most important thing in the programming language is the name. A language
will not succeed without a good name. I have recently invented a very good
name and now I am looking for a suitable language."
-- D. E. Knuth
**This page is about the Nimrod programming language, which combines Lisp's
power with Python's readability and C++'s performance.**
Welcome to the Nimrod programming language
------------------------------------------
**Nimrod** is a new statically typed, imperative
programming language, that supports procedural, functional, object oriented and
generic programming styles while remaining simple and efficient. A special
feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree
(*AST*) is part of the specification - this allows a powerful macro system which
can be used to create domain specific languages.
*Nimrod* is a compiled, garbage-collected systems programming language
which has an excellent productivity/performance ratio. Nimrod's design
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
priority).
Some more of Nimrod's highlights:
* Native code generation (currently via compilation to C).
* Garbage collection, but not dependant on a Virtual Machine.
* Portable: The Nimrod Compiler runs on Windows, Linux and Mac OS X.
Porting to other platforms is easy.
* System programming features: Ability to manage your own memory and access the
hardware directly. You will never have to use C/C++ for that again!
* Zero-overhead iterators.
* Modern type system with local type inference, tuples, variants, etc.
* User-defineable operators; new operators often easier to read than
overloaded ones.
* High level datatypes: strings, sets, sequences, etc.
* Compile time evaluation without resorting to meta-programming facilities.
* Forward compability: If later versions of the language introduce new
keywords old code won't break!
* Bindings to GTK2, the Windows API, the POSIX API. New bindings are easily
generated in a semi-atomatic way.
* A plugable parser system: If you don't like Nimrod's syntax, you can plug
in a parser and a source renderer for your own syntax!
* A documentation generator with an internal reStructuredText parser: This
can also be used to write documentation that is not embedded into the
source code. This makes documentation writing a joy (well, almost).
* A Pascal to Nimrod conversion utility: This is particularly useful for
generating bindings to any library which has a Pascal binding
(these are many!).
..
The Zen of Nimrod
-----------------
* Faster computers are for solving bigger problems, not wasting cycles.
* Static is better than dynamic: More efficient, more understandable,
better verifyable.
* Don't criple the language in the name of simplicity.
* Be backward and *forward* compatible.

View File

@@ -1 +0,0 @@
Visit our project page at Launchpad: https://launchpad.net/nimrod.

View File

@@ -1,31 +0,0 @@
====
News
====
Developers needed
=================
Yes, this is nothing new. If you are interested to help designing and
implementing the new programming language Nimrod, visit our project page at
Launchpad: https://launchpad.net/nimrod and contact me.
2008-08-22 Version 0.6.0 released
=================================
Nimrod version 0.6.0 has been released! Get it `here <./download.html>`_.
**This is the first version of the compiler that is able to compile itself!**
A nice side-effect from this is that a source-based installation does not
depend on FreePascal any longer.
Changes:
* various bug fixes, too many to list them here
* cleaned up the type system: records are now superfluous and not
supported anymore
* improved the performance of the garbage collector
* new modules in the library:
- ``parseopt``: a simple to use command line parser
- ``hashes``: efficient computation of hash values
- ``strtabs``: efficient mapping from strings to strings
- ``parsecfg``: an efficient configuration file parser
* macros and compile-time evaluation implemented (however, still experimental)
* generics implemented (however, still experimental)

View File

@@ -1,138 +0,0 @@
===========================================
Questions and Answers
===========================================
General
=======
`What is Nimrod?`:Q:
**Nimrod** is a new statically typed, imperative
programming language, that supports procedural, functional, object oriented and
generic programming styles while remaining simple and efficient. A special
feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree
(*AST*) is part of the specification - this allows a powerful macro system which
can be used to create domain specific languages.
`How is Nimrod licensed?`:Q:
The Nimrod compiler is GPL licensed, the runtime library is LGPL licensed.
This means that you can use any license for your own programs developed with
Nimrod. If I receive enough requests with good arguments, I may change the
license of Nimrod to the BSD license.
Installation
============
`Is bootstrapping without Python possible?`:Q:
Yes. You then have to compile by hand. It is not difficult (but it is not
easy either). Please read the code in the ``koch.py`` script how this is can
be accomplished (look for the ``cmd_boot`` routine).
`A source-based download depending on the platform?`:Q:
The reason is that the C code *generated* by Nimrod is not
portable (the compiler itself is, of course!). The generated C
code is used for the installation, so you have to pick the right package.
`Why is compilation so slow?`:Q:
*Compilation* is fast. The problem is that Nimrod always
recompiles **everything**. In the next version, only modules that
have changed will be recompiled.
Another issue may be that the C compiler that is called by Nimrod is slow.
Especially GCC's compile times are a bad joke. On Linux you may be able to get
`Tiny C <http://fabrice.bellard.free.fr/tcc/>`_ to work. TCC has excellent
compile times. You should not use TCC for producing the release version
though, as it has no optimizer.
`Which version of Freepascal is needed to compile Nimrod?`:Q:
Version 2.0.0 or later. Earlier development versions like 1.9.6 may work,
but 1.0.10 won't. Note that I have never compiled Nimrod with FPC's
optimizer turned on; it may break things due to bugs in FPC (yes, this has
happend!).
`How do I build a shared library?`:Q:
This is currently not supported.
`How do I use a different C compiler than the default one?`:Q:
Edit the ``config/nimrod.cfg`` file.
Change the value of the ``cc`` variable to one of the following:
============== ============================================
Abbreviation C/C++ Compiler
============== ============================================
``dmc`` Digital Mars C++
``wcc`` Watcom C++ (now unsupported!)
``bcc`` Borland C++ (including Borland C++Builder)
``vcc`` Microsoft's Visual C++
``gcc`` Gnu C
``pcc`` Pelles C (now unsupported!)
``lcc`` Lcc-win32 (now unsupported!)
``tcc`` Tiny C (now unsupported!)
``llvm_gcc`` LLVM-GCC compiler
``icc`` Intel C++ compiler
``ucc`` Generic UNIX C compiler
============== ============================================
If your C compiler is not in the above list, try using the
*generic UNIX C compiler* (``ucc``). If the C compiler needs
different command line arguments try the ``--passc`` and ``--passl`` switches.
`The linker outputs strange errors about missing symbols`:Q:
I have seen this bug only with the GNU linker. The reason for this unknown.
Try recompiling your code with the ``--c_file_cache:off`` command line switch.
`Calling the C compiler fails - what's wrong?`:Q:
First try to edit the path to your C compiler in the
``config/nimrod.cfg`` file. For the Windows version bundled with
LLVM search for the line containing ``llvm_gcc.path``. Set this
variable to the ``bin`` directory of LLVM.
Many C compilers need special environment variables to work
properly. Although Nimrod tries hard to set them correctly (see
``extccomp.pas`` for details), this may fail if you use a
different version of the C compiler. The solution is to
ensure that all environment variables are set correctly.
You can set environment variables temporarily by using the
``@putenv "key" "val"`` directive in the ``config/nimrod.cfg``
configuration file. There are also ``@append_env`` and
``@prepend_env`` directives for appending or prepending
to environment variables.
`Calling the C compiler still fails`:Q:
Try to call the C compiler directly by doing the following::
nimrod --compile_only --gen_script your_path/your_file
sh ./your_path/rod_gen/compile_your_file.sh
Questions about the Nimrod language
===================================
`How to overload the ``in`` operator?`:Q:
The ``in`` and ``not_in`` operators are implemented as templates. The reason is
that these operators need a reverse unification algorithm (don't ask). See the
``system.nim`` module for a deeper explanation. The solution is to implement a
simple ``in_Operator`` proc where the arguments are the other way round::
proc in_operator(s: string, c: char): bool =
for x in items(s):
if x == c: return True
return False
writeln(stdout, 'z' in "abcdz") # now works!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

View File

@@ -1,398 +0,0 @@
/* global */
html{height: 100%;}
body
{ font-family: verdana, arial, sans-serif;
padding: 0px;
margin: 0px;
font-size: .70em;
}
pre, tt
{
font-size: 130%;
}
p
{ margin: 0px;
padding: 0px 0px 16px 0px;
line-height: 1.7em;
}
#column2 h1
{ font-family: arial, sans-serif;
letter-spacing: .1em;
}
#column2 h2
{ margin: 0px;
padding: 0px 0px 4px 0px;
font-size: 100%;
}
img{border: 0px;}
a.reference{outline: none;}
/* image positioning - left, right and center */
.left
{ float: left;
padding: 0px 8px 0px 0px;
}
.right
{ float: right;
padding: 0px 0px 0px 8px;
}
.center
{ display: block;
text-align: center;
margin: 0 auto;
}
/* block quote */
blockquote
{ margin: 20px 0px 20px 0px;
padding: 10px 20px 0px 20px;
border-left: 8px solid;
}
/* unordered list */
ul
{ margin: 2px 0px 16px 16px;
padding: 0px;
}
ul li
{ list-style-type: square;
margin: 0px 0px 6px 0px;
padding: 0px;
}
/* ordered list */
ol
{ margin: 8px 0px 0px 24px;
padding: 0px;
}
ol li
{ margin: 0px 0px 11px 0px;
padding: 0px;
}
/* main container */
#main
{ width: 780px;
margin-left: auto;
margin-right: auto;
}
/* links above the logo / footer */
#links, #footer
{ margin-left: auto;
margin-right: auto;
padding: 10px 21px 0px 19px;
width: 720px;
height: 26px;
font-size: 94%;
text-transform: uppercase;
}
#links{text-align: right;}
#footer{text-align: center;}
#links a.reference, #footer a.reference{text-decoration: none;}
#links a.reference:hover, #footer a.reference:hover{text-decoration: underline;}
/* logo */
#logo
{ margin-left: auto;
margin-right: auto;
width: 760px;
height: 100px;
text-align: left;
}
#logo h1
{ margin: 0px;
padding: 41px 0px 0px 19px;
font-size: 150%;
letter-spacing: .2em;
}
/* navigation menu */
#menu
{ height: 42px;
width: 760px;
margin-left: auto;
margin-right: auto;
}
#menu ul{margin: 0px auto;}
#menu li
{ float: left;
margin: 0px;
padding: 0px;
}
#menu li a, #menu li a:visited
{ display: block;
float: left;
height: 37px;
text-decoration: none;
padding: 3px 19px 2px 19px;
text-transform: uppercase;
color: #DBD7D1;
}
/* main content */
#content
{ margin-left: auto;
margin-right: auto;
width: 760px;
height: auto;
padding: 0px;
overflow: hidden;
}
/* column 1 - contains sidebar items */
#column1
{ width: 207px;
float: right;
padding: 16px 0px 15px 0px;
}
.sidebaritem
{ text-align: left;
width: 188px;
float: left;
margin: 0px 0px 25px 0px;
}
.sbihead
{ height: 14px;
width: 188px;
padding: 5px 0px 5px 19px;
text-transform: uppercase;
}
.sbihead h1
{ padding: 0px;
margin: 0px;
font-weight: bold;
font-size: 112%;
}
#column1 h1 a, #column1 h1 a:hover, #column1 h1 a:visited
{
text-decoration:none;
font-size: 80%;
}
.sbicontent{padding: 14px 8px 8px 19px;}
.sbicontent p
{ line-height: 14px;
padding: 0px 0px 8px 0px;
}
.sbilinks{padding: 0px;}
.sbilinks ul{margin: 0px auto;}
.sbilinks li
{ margin: 0px;
float: left;
list-style: none;
}
.sbilinks li a.reference , .sbilinks li a.reference:hover
{ float: left;
height: 16px;
text-decoration: none;
padding: 5px 0px 4px 19px;
width: 188px;
border: 0px;
}
/* column 2 - page content */
#column2
{ text-align: justify;
width: 512px;
float: left;
padding: 12px 3px 15px 19px;
}
#column2 h1
{ padding: 6px 0px 4px 0px;
margin: 0px 0px 12px 0px;
border-bottom: 1px solid;
/* font-size: 150%; */
text-transform: uppercase;
font-weight: normal;
}
.sidebaritem a.reference , .sidebaritem a.reference:hover
{ padding: 0px 0px 2px 0px;
text-decoration: none;
border-bottom: 1px dashed;
}
.sidebaritem a.reference:hover{border-bottom: 1px solid;}
/* contact page - form layout */
form{margin-top: 0px;}
div.row
{ clear: both;
width: 448px;
}
div.row span.formlabel
{ float: left;
width: 150px;
text-align: left;
}
div.row span.forminput
{ float: right;
text-align: right;
}
div.spacer
{ clear: both;
width: 80px;
}
input, textarea
{ width: 259px;
font-family: verdana, arial, sans-serif;
border: 1px solid;
font-size: 100%;
margin: 2px;
}
.submit
{ font-family: verdana, arial, sans-serif;
border: 1px solid;
width: 70px;
height: 22px;
cursor: pointer;
font-size: 100%;
}
html{height: 100%;}
body
{ background: #837560;
color: #70695A;
}
blockquote
{ background: #FFFFFF;
color: #70695A;
border-color: #767676;
}
#main
{ background: #FFFFFF url(back.png) repeat-y;
color: #70695A;
}
#links, #footer, #menu, #menu li a.reference
{ background: #FFFFFF url(menu.png);
color: #DBD7D1;
border-color: #D7D7D7;
}
#links a.reference, #footer a.reference,
#links a.reference:hover, #footer a.reference:hover
{ background: transparent;
color: #DBD7D1;
}
#logo
{ background: #FFFFFF url(logo.jpg) no-repeat;
color: #70695A;
}
#logo h1
{ background: transparent;
color: #FFFFFF;
}
#column2 h1, #column2 h1 a.reference,
#column2 h2, #column2 h2 a.reference
{ background: transparent;
color: #CE7014;
border-color: #CAAE90;
font-size: 150%;
}
#column2 h2, #column2 h2 a.reference {
font-size: 110%;
}
#menu li a:hover, #menu li a#selected,
#menu li a#selected:hover
{ background: #FFFFFF url(menu_hover.png);
color: #70695A;
}
#content
{ background: transparent;
color: #111; /* #70695A; */
}
#column2 a.reference, #column2 a.reference:hover {
color: #fb7f03;
}
#column2 a.reference:visited {
color: #7b5224;
}
.sidebaritem, .sidebaritem a.reference, .sidebaritem a.reference:hover
{ background: transparent;
color: #DBD7D1;
}
.sbihead
{ background: #FFFFFF url(sbi_header.png);
color: #70695A;
}
.sbihead h1
{ background: transparent;
color: #70695A;
}
.sbilinks li a.reference
{ background: #FFFFFF url(link.png);
color: #DBD7D1;
}
.sbilinks li a.reference:hover
{ background: #B7B7B7;
color: #CE7014;
}
input, textarea
{ background: #FFFFFF;
color: #70695A;
border-color: #CAAE90;
}
span.Q {
font-size: 120%;
font-weight: bold;
}
span.newsdate {
font-size: 110%;
font-weight: bold;
}

View File

@@ -1,62 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Nimrod Programming System</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" type="text/css" href="style/style.css" />
</head>
<body>
<div id="main">
<div id="links">
<!-- **** INSERT LINKS HERE **** -->
</div>
<div id="logo"><h1>Nimrod Programming System</h1></div>
<div id="content">
<div id="menu">
<ul>
#for $name, $t in $tabs
#if $tab == $t
<li><a id="selected" href="${t}.html" title = "Nimrod - $name">$name</a></li>
#else
<li><a href="${t}.html" title = "Nimrod - $name">$name</a></li>
#end if
#end for
</ul>
</div>
<div id="column1">
<div class="sidebaritem">
<div class="sbihead">
<h1>latest news</h1>
</div>
<div class="sbicontent">
$ticker
</div>
</div>
<div class="sidebaritem">
<div class="sbihead">
<h1>additional links</h1>
</div>
<div class="sbilinks">
<!-- **** INSERT ADDITIONAL LINKS HERE **** -->
<ul>
<li><a class="reference" href="http://llvm.org">LLVM</a></li>
<li><a class="reference" href="http://gcc.gnu.org">GCC</a></li>
</ul>
</div>
</div>
</div>
<div id="column2">
$content
</div>
</div>
<div id="footer">
copyright &copy; 2008 Andreas Rumpf | Last update: $lastupdate
| <a class="reference" href="http://validator.w3.org/check?uri=referer">XHTML 1.1</a>
| <a class="reference" href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>
| <a class="reference" href="http://www.dcarter.co.uk">design by dcarter</a>
</div>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,137 +0,0 @@
/*
:Authors: Ian Bicking, Michael Foord
:Contact: fuzzyman@voidspace.org.uk
:Date: 2005/08/26
:Version: 0.1.0
:Copyright: This stylesheet has been placed in the public domain.
Stylesheet for Docutils.
Based on ``blue_box.css`` by Ian Bicking
and ``html4css1.css`` revision 1.46.
*/
@import url(html4css1.css);
body {
font-family: Arial, sans-serif;
}
em, i {
/* Typically serif fonts have much nicer italics */
font-family: Times New Roman, Times, serif;
}
a.target {
color: blue;
}
a.target {
color: blue;
}
a.toc-backref {
text-decoration: none;
color: black;
}
a.toc-backref:hover {
background-color: inherit;
}
a:hover {
background-color: #cccccc;
}
div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning {
background-color: #cccccc;
padding: 3px;
width: 80%;
}
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
text-align: center;
background-color: #999999;
display: block;
margin: 0;
}
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
color: #cc0000;
font-family: sans-serif;
text-align: center;
background-color: #999999;
display: block;
margin: 0;
}
h1, h2, h3, h4, h5, h6 {
font-family: Helvetica, Arial, sans-serif;
border: thin solid black;
/* This makes the borders rounded on Mozilla, which pleases me */
-moz-border-radius: 8px;
padding: 4px;
}
h1 {
background-color: #444499;
color: #ffffff;
border: medium solid black;
}
h1 a.toc-backref, h2 a.toc-backref {
color: #ffffff;
}
h2 {
background-color: #666666;
color: #ffffff;
border: medium solid black;
}
h3, h4, h5, h6 {
background-color: #cccccc;
color: #000000;
}
h3 a.toc-backref, h4 a.toc-backref, h5 a.toc-backref,
h6 a.toc-backref {
color: #000000;
}
h1.title {
text-align: center;
background-color: #444499;
color: #eeeeee;
border: thick solid black;
-moz-border-radius: 20px;
}
table.footnote {
padding-left: 0.5ex;
}
table.citation {
padding-left: 0.5ex
}
pre.literal-block, pre.doctest-block {
border: thin black solid;
padding: 5px;
}
.image img { border-style : solid;
border-width : 2px;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
font-size: 100%;
}
code, tt {
color: #000066;
}