├── .gitignore
├── LICENSE
├── README.md
├── build.js
├── docs
├── .gitignore
├── _config.yml
├── _includes
│ ├── highlight.html
│ └── icons
│ │ ├── logo.svg
│ │ └── reset.svg
├── _layouts
│ ├── default.html
│ └── page.html
├── _scripts
│ ├── build-co-lib.sh
│ └── optimgs.sh
├── doc
│ ├── chaitin
│ │ ├── chaitin.js
│ │ ├── common.js
│ │ ├── index.css
│ │ ├── index.html
│ │ ├── slc.js
│ │ └── svg.js
│ ├── index.md
│ ├── ir.md
│ ├── patterns.md
│ ├── r
│ │ ├── build-pkg.svg
│ │ ├── compiler-pipeline.svg
│ │ ├── parser-pipeline.svg
│ │ └── shared-resources.svg
│ ├── spec.md
│ ├── stack.md
│ └── stack
│ │ ├── index.md
│ │ ├── stack-01.svg
│ │ ├── stack-02.svg
│ │ ├── stack-03.svg
│ │ ├── stack-04.svg
│ │ ├── stack-05.svg
│ │ ├── stack-06.svg
│ │ ├── stack-07.svg
│ │ ├── stack-08.svg
│ │ ├── stack-09.svg
│ │ ├── stack-10.svg
│ │ ├── stack-11.svg
│ │ └── stack-12.svg
├── index.md
├── play
│ ├── co.js
│ ├── co.js.map
│ └── index.html
├── r
│ ├── favicon.ico
│ ├── favicon.svg
│ ├── highlight.js
│ ├── initdoc.js
│ ├── style.css
│ ├── ted.css
│ ├── ted.js
│ └── uibindings.js
└── serve.sh
├── example
├── base64.xl
├── basic.xl
├── bufcmp.xl
├── cyclic-type-ref.co
├── deadcode.co
├── declarations.xl
├── fun-return-types.xl
├── function-call-rest.co
├── function-call.co
├── functions.co
├── generic-typevar-sep.co
├── generics.co
├── id1.xl
├── identifiers.xl
├── imports.xl
├── inline-branch-elim.co
├── lists.co
├── literal-num.xl
├── macro-idea1.co
├── mix1.xl
├── numbers.xl
├── operators.xl
├── ownership.xl
├── record.co
├── return-types.xl
├── scope.xl
├── scope2.xl
├── scope3.xl
├── scope4.xl
├── slice-and-index.xl
├── ssa-bug1.co
├── ssa1.co
├── text.xl
├── tuples.xl
├── typeless-fun.xl
└── types.xl
├── misc
├── fmtduration.c
├── gen-keywords.js
├── gen-unicode-data.js
├── gen-wasm.js
├── gen.js
├── language.md
├── parse-debugger.html
├── test-nbits.js
└── test_rewrite_rules.co
├── package-lock.json
├── package.json
├── src
├── all_tests.ts
├── api.ts
├── arch
│ ├── README.md
│ ├── arch_covm.rewrite
│ ├── arch_covm_ops.ts
│ ├── arch_generic_ops.ts
│ ├── describe.ts
│ ├── gen.ts
│ ├── ops_template.ts
│ ├── run.sh
│ └── tsconfig.json
├── asm
│ ├── asm.ts
│ └── fun.ts
├── ast.ts
├── ast
│ ├── astio.ts
│ ├── gen
│ │ ├── ast.ts
│ │ ├── main.ts
│ │ ├── run.sh
│ │ └── tsconfig.json
│ ├── nodes.ts
│ ├── repr.ts
│ ├── scope.ts
│ ├── test
│ │ ├── ast_test.ts
│ │ ├── empty.co
│ │ ├── identifiers.co
│ │ ├── literal-number-i64.co
│ │ ├── template-expansion.co
│ │ ├── template-future-def.co
│ │ ├── template-pre-def.co
│ │ ├── template-var-sep.co
│ │ └── template.co
│ ├── transform.ts
│ └── visit.ts
├── bind.ts
├── btree.ts
├── bytestr.ts
├── cli.ts
├── debug.ts
├── diag.ts
├── error.ts
├── global.d.ts
├── global.js
├── int64.ts
├── int64.wast
├── int64_rand.ts
├── int64_rand.wast
├── int64_test.ts
├── intgraph.ts
├── intgraph_test.ts
├── intparse.ts
├── ir
│ ├── arch.ts
│ ├── arch_info.ts
│ ├── blocktree.ts
│ ├── builder.ts
│ ├── config.ts
│ ├── consteval.ts
│ ├── copyelim.ts
│ ├── deadcode.ts
│ ├── dom.ts
│ ├── layout.ts
│ ├── localslot.ts
│ ├── loopnest.ts
│ ├── lower.ts
│ ├── op.ts
│ ├── ops.ts
│ ├── opselect.ts
│ ├── opt_cf.ts
│ ├── opt_dce.ts
│ ├── passes.ts
│ ├── phielim.ts
│ ├── postorder.ts
│ ├── reg.ts
│ ├── reg_desiredstate.ts
│ ├── regalloc.ts
│ ├── repr.ts
│ ├── rewrite.ts
│ ├── rewrite_covm.ts
│ ├── shortcircuit.ts
│ ├── ssa.ts
│ └── vm.ts
├── main.ts
├── num.ts
├── numconv.ts
├── numeval.ts
├── nummath.ts
├── parse-debugger.ts
├── parser.ts
├── path.ts
├── pathmap.ts
├── pos.ts
├── resolve.ts
├── scan_num_test.ts
├── scanner.ts
├── scanner_test.ts
├── sexpr.ts
├── strtou.ts
├── template.ts
├── termstyle.ts
├── test.ts
├── time.ts
├── time_fmtduration.wast
├── token.ts
├── typecompat.ts
├── typeset.ts
├── unicode.ts
├── universe.ts
├── utf8.ts
├── util.ts
└── vm
│ └── vm.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.a
3 | *.d
4 | *.gz
5 | /*.sublime-*
6 | src/*.wast.wasm
7 | _local
8 | /.build-cache
9 | /dist
10 | /report.*
11 | .DS_Store
12 | node_modules
13 | misc/UnicodeData.txt
14 | misc/emoji-data.txt
15 | * copy
16 |
17 | # code generator program output:
18 | src/**/.src-*.js
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Rasmus Andersson
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Co programming language
2 |
3 | A programming language and optimizing compiler.
4 |
5 | This is a project about:
6 |
7 | - Designing a practical, general-purpose programming language
8 | - Statically typed, but the compiler does as much for you as possible
9 | - Simple syntax, few built-ins
10 | - More like Go than JavaScript
11 | - Optimizing compiler
12 | - Input-language agnostic
13 | - Intermediate Representation in SSA form
14 | - Flexible target architecture (x86, amd64, vm, wasm, etc.)
15 | - Pipelined rather than progressive
16 | - scanning source code into the parser
17 | - parser passes AST chunks to the IR builder
18 | - IR builder optimizes the chunks and then passes them to the code generator
19 | - All this happens in a streaming fashion
20 | - But each step can be easily separated and run independendly, making
21 | it easy to inspect the state of the compiler at various steps of the
22 | process.
23 | - Using no exernal libraries
24 | - Portable (can run in a web browser)
25 | - Simplify codebase
26 | - Minimize risk of security concerns
27 | - Maximize startup performance
28 |
29 |
30 | ## Using
31 |
32 | Requirements: [nodejs](https://nodejs.org/) >=8.0
33 |
34 | Building:
35 | - Setup: `npm install`
36 | - Build incrementally: `./build.js -w`
37 | - Run: `./dist/co.g`
38 |
39 | Some useful things:
40 | - Build debug version in one go: `./build.js`
41 | - Build optimized production version: `./build.js -O`
42 | - Run unit tests before main program: `./dist/co.g -test`
43 | - Run unit tests and exit: `./dist/co.g -test-only`
44 | - Print source diagnostics report and exit: `./dist/co.g -nobuild`
45 | - Live coding setup:
46 | - Terminal 1: `./build.js -w`
47 | - Terminal 2: `autorun dist/co.g`
48 | - You'll need [`autorun`](https://github.com/rsms/autorun)
49 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | /_site
2 | .jekyll*
3 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | port: 3000
2 | lsi: false
3 | permalink: /:title
4 | markdown: kramdown
5 | # Since GH pages override this to "true", we test this value to see if we are running locally
6 | safe: false
7 | include: [".well-known"]
8 | # highlighter: none
9 | # syntax_highlighter: none
10 | kramdown:
11 | input: GFM
12 | auto_ids: true
13 | hard_wrap: false
14 | # transliterated_header_ids: true
15 | # syntax_highlighter: null
16 | # syntax_highlighter: "coderay"
17 | syntax_highlighter_opts:
18 | disable: true
19 |
--------------------------------------------------------------------------------
/docs/_includes/highlight.html:
--------------------------------------------------------------------------------
1 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/_includes/icons/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_includes/icons/reset.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 | {% capture build_version
2 | %}{{ site.time | date: "%Y%m%d%H%M%S" }}{%
3 | endcapture %}{%
4 | capture url_root
5 | %}{% if site.safe == false %}/{% else %}/co/{% endif
6 | %}{%
7 | endcapture %}
8 |
9 |
10 |
11 | {% if page.title %}{{ page.title }} — {% endif %}The Co programming language
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {% if page.title %}
23 |
24 |
25 | {% if page.description %}
26 |
27 |
28 |
29 | {% else %}
30 |
31 | {% endif %}
32 | {% else %}
33 |
34 | {% endif %}
35 | {% if page.og_image_url %}
36 |
37 |
38 | {% endif %}
39 |
40 |
41 |
42 |
43 |
44 |
45 | {% if page.header == "minimal" %}
46 |
47 | {% include icons/logo.svg %}
48 |
49 | {% else %}
50 |
51 | {% include icons/logo.svg %}
52 |
53 |
69 |
83 | {% endif %}
84 |
85 | {{ content }}
86 |
87 |
88 |
89 | {% include highlight.html %}
90 |
91 |
92 |
--------------------------------------------------------------------------------
/docs/_layouts/page.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 |
7 |
--------------------------------------------------------------------------------
/docs/_scripts/build-co-lib.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | cd "$(dirname "$0")/../.."
3 |
4 | ./build.js -O -lib -o docs/play/co.js
5 |
--------------------------------------------------------------------------------
/docs/_scripts/optimgs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -o errexit -o pipefail -e
3 | cd "$(dirname "$0")/.."
4 |
5 | # svg
6 | for f in _includes/icons/*.svg r/*.svg doc/r/*.svg; do
7 | echo "svgo $f"
8 | svgo --config='{"plugins":[{"transformsWithOnePath":{}},{"removeViewBox":{}},{"removeAttrs":{"attrs":["figma.+"]}},{"removeTitle":{}},{"removeDesc":{"removeAny":true}}]}' \
9 | --multipass \
10 | -q \
11 | "$f" &
12 | done
13 |
14 | pushd r >/dev/null
15 | for f in *.ico; do
16 | echo "pngcrush $f"
17 | TMPNAME=.$f.tmp
18 | (pngcrush -q "$f" "$TMPNAME" && mv -f "$TMPNAME" "$f") &
19 | done
20 | popd
21 |
22 | wait
23 |
--------------------------------------------------------------------------------
/docs/doc/chaitin/chaitin.js:
--------------------------------------------------------------------------------
1 |
2 | class InterferenceGraph {
3 | constructor(svg) {
4 | this.nodes = {}
5 | this.edges = {}
6 | this.svg = Svg(svg)
7 | }
8 |
9 | // renderGraph( svgel : SvgElement, graph : Map> ) : void
10 | renderGraph(values) {
11 | // console.log('edges', JSON.stringify(edges))
12 | let nvals = values.size
13 |
14 | // 360 deg in radians = PI•2
15 | let radmax = Math.PI * 2
16 |
17 | // radius and text offset of a value circle
18 | let circleR = 18
19 | let circleSpacing = circleR * 2
20 | let textYOffset = 4
21 |
22 | // guide outer margin
23 | let guideMargin = circleR
24 |
25 | // graph svg object
26 | let svg = this.svg
27 |
28 | // empty svg
29 | while (svg.n.childNodes.length) {
30 | svg.n.removeChild(svg.n.childNodes[0])
31 | }
32 |
33 | // guide radius
34 | // maximum guide is size of graph minus some outer margin
35 | let guideRMax = (Math.min(svg.height, svg.width) / 2) - guideMargin
36 | // guide size is circumference computed from number of values + spacing
37 | // Circumference -> Radius: R = C/(2•PI)
38 | let guideR = (((circleR * 2) + circleSpacing) * nvals) / radmax
39 | // scale down if guideR > guideRMax
40 | let scale = 1, pt = 1
41 | if (guideR > guideRMax) {
42 | scale = guideRMax / guideR
43 | pt = 1 / scale
44 | let width = svg.width / scale
45 | let height = svg.height / scale
46 | svg.viewBox = {
47 | x: -(width - svg.width) / 2,
48 | y: -(height - svg.height) / 2,
49 | width,
50 | height
51 | }
52 | }
53 |
54 | let sceneCenter = { x: svg.width/2, y: svg.height/2 }
55 |
56 | let guideCircle = svg.add('circle', {
57 | class: 'guide',
58 | cx: sceneCenter.x, cy: sceneCenter.y,
59 | r: guideR,
60 | })
61 |
62 | // nodes contains info on all node graphics
63 | let nodes = {} // { id : { x : int, y : int, circleNode : SvgNode } }
64 |
65 | // groups for nodes
66 | let nodesg = svg.add('g', { class: 'nodes' })
67 |
68 | // // reverse order of names since the graph is built bottom-up, but
69 | // // really we want to think of it as top-down (the SLC, that is.)
70 | // let names = Array.from(values.keys()).reverse()
71 |
72 | // sort order of names since the graph is built bottom-up
73 | let names = Array.from(values.keys()).sort()
74 |
75 | // create nodes for names
76 | for (let i = 0; i < names.length; i++) {
77 | let name = names[i]
78 |
79 | let rad = ((i / nvals) * radmax) + (Math.PI*1.5)
80 | // Math.PI*1.5 = start at top
81 | let x = sceneCenter.x + (guideR * Math.cos(rad))
82 | let y = sceneCenter.y + (guideR * Math.sin(rad))
83 |
84 | let g = nodesg.add('g', { class: 'val' })
85 | let circleNode = g.add('circle', {
86 | class: 'node',
87 | cx: x,
88 | cy: y,
89 | r: circleR,
90 | 'stroke-width': 1 * pt,
91 | fill: 'none',
92 | })
93 | g.add('text', { x, y: y + textYOffset, 'text-anchor': 'middle' }, name)
94 |
95 | nodes[name] = { x, y, g, circleNode }
96 | }
97 |
98 | // relationships
99 | let relsg = svg.add('g', { class: 'rels' })
100 | let edges = {}
101 |
102 | for (let p of values) {
103 | let id1 = p[0]
104 | for (let id2 of p[1]) {
105 | let key = this.edgeKey(id1, id2)
106 | if (!(key in edges)) {
107 | edges[key] = { ids: [ id1, id2 ] }
108 | }
109 | }
110 | }
111 |
112 | for (let key in edges) {
113 | let v = edges[key]
114 |
115 | let node1 = nodes[v.ids[0]]
116 | let node2 = nodes[v.ids[1]]
117 |
118 | let x1 = node1.x, y1 = node1.y
119 | let x2 = node2.x, y2 = node2.y
120 |
121 | // move line points out to edges of the circles (offset by circleR)
122 | let angle = Math.atan2(y2 - y1, x2 - x1)
123 | let offsx = Math.cos(angle) * circleR
124 | let offsy = Math.sin(angle) * circleR
125 | x1 += offsx
126 | y1 += offsy
127 | x2 -= offsx
128 | y2 -= offsy
129 |
130 | let line = relsg.add('line', {
131 | x1, y1, x2, y2,
132 | 'stroke-width': 1 * pt,
133 | class: 'rel',
134 | })
135 |
136 | v.line = line
137 | }
138 |
139 | this.nodes = nodes
140 | this.edges = edges
141 | }
142 |
143 |
144 | edgeKey(id1, id2) {
145 | return id1 < id2 ? (id1 + " " + id2) : (id2 + " " + id1)
146 | }
147 |
148 | } // class Chaitin
149 |
--------------------------------------------------------------------------------
/docs/doc/chaitin/common.js:
--------------------------------------------------------------------------------
1 | function $(q, e) {
2 | return (e || document).querySelector(q)
3 | }
4 |
5 | function $$(q, e) {
6 | return [].slice.apply((e || document).querySelectorAll(q))
7 | }
8 |
9 | // monotime() :number
10 | let monotime = (
11 | typeof performance != 'undefined' && performance.now ?
12 | performance.now.bind(performance) :
13 | () => (new Date()).getTime() * 1000
14 | )
15 |
16 | let _templateCache = {}
17 | function template(id) {
18 | let t = _templateCache[id]
19 | if (!t) {
20 | t = document.getElementById('template-' + id)
21 | if (!t) {
22 | console.error('template "'+id+'" not found')
23 | return
24 | }
25 | t.parentNode.removeChild(t)
26 | t.removeAttribute('id')
27 | _templateCache[id] = t
28 | }
29 | return t.cloneNode(true)
30 | }
31 |
--------------------------------------------------------------------------------
/docs/doc/chaitin/slc.js:
--------------------------------------------------------------------------------
1 | // straight-line code
2 | (function(slc){
3 |
4 |
5 | function tokenize(src) {
6 | return src
7 | .replace(/^\/\/[^\n]*/gm, '')
8 | .replace(/[\n;]+/g, ';')
9 | .split(/[\t ]*\b[\t ]*/)
10 | }
11 |
12 | function value(vars, id, op, operands, consts) {
13 | // console.log('value', id, op, operands)
14 | if (operands) for (let id of operands) {
15 | let v = vars.get(id)
16 | if (!v) {
17 | vars.set(id, { id: id, type: 'implicit', uses: 1 })
18 | } else {
19 | v.uses++
20 | }
21 | }
22 |
23 | let v = {
24 | id,
25 | op,
26 | operands,
27 | consts,
28 | uses: 0,
29 | }
30 | vars.set(id, v)
31 | return v
32 | }
33 |
34 | function parse(src) {
35 | let tokens = tokenize(src.trim())
36 | // console.log(tokens.join(' '))
37 | let dst, op, operands, consts, seenAssign
38 | let values = []
39 | let vars = new Map()
40 |
41 | const reset = () => {
42 | dst = ''
43 | op = '='
44 | operands = []
45 | consts = []
46 | seenAssign = false
47 | }
48 |
49 | reset()
50 |
51 | for (let i = 0; i < tokens.length; i++) {
52 | let t = tokens[i]
53 | switch (t) {
54 |
55 | case '':
56 | break
57 |
58 | case '=':
59 | seenAssign = true
60 | break
61 |
62 | case ';':
63 | values.push(value(vars, dst, op, operands, consts))
64 | reset()
65 | break
66 |
67 | case '+':
68 | case '-':
69 | case '*':
70 | case '/':
71 | op = t
72 | break
73 |
74 | default:
75 | if (!t[0].match(/\w/)) {
76 | // bad syntax. e.g. "+;" from "a = b +"
77 | throw new Error('invalid name ' + JSON.stringify(t))
78 | }
79 | if (dst == '') {
80 | dst = t
81 | } else {
82 | if (t.match(/^\d/)) {
83 | consts.push(t)
84 | } else {
85 | operands.push(t)
86 | }
87 | }
88 |
89 | }
90 | }
91 |
92 | if (seenAssign) {
93 | values.push(value(vars, dst, op, operands, consts))
94 | }
95 |
96 | return values
97 | }
98 |
99 |
100 |
101 | slc.parse = parse
102 |
103 |
104 | })(this.slc = {});
105 |
--------------------------------------------------------------------------------
/docs/doc/chaitin/svg.js:
--------------------------------------------------------------------------------
1 |
2 | function SvgNode(tag, attrs, text) {
3 | var n = document.createElementNS('http://www.w3.org/2000/svg', tag)
4 | if (attrs) for (let k in attrs) {
5 | n.setAttributeNS(null, k, attrs[k])
6 | }
7 | if (text) n.textContent = text
8 | return Object.create(SvgNode.prototype, {
9 | n: {enumerable:true, value:n},
10 | _attrs: { value:attrs },
11 | })
12 | }
13 |
14 | // add(tag, attrs?, text?)
15 | SvgNode.prototype.add = function (tag, attrs, text) {
16 | let n = SvgNode(tag, attrs, text)
17 | this.n.appendChild(n.n)
18 | return n
19 | }
20 |
21 | // get attr(name) => value
22 | // set attr(name, value)
23 | SvgNode.prototype.attr = function (name, value) {
24 | if (arguments.length > 1) {
25 | this._attrs[name] = value
26 | this.n.setAttributeNS(null, name, value)
27 | } else {
28 | return (
29 | name in this._attrs ? this._attrs[name] :
30 | this.n.getAttributeNS(null, name)
31 | )
32 | }
33 | }
34 |
35 |
36 |
37 | function Svg(n) {
38 | return Object.create(Svg.prototype, {
39 | n: {enumerable:true, value:n},
40 | _attrs: { value: {} },
41 | })
42 | }
43 |
44 | Svg.prototype.add = SvgNode.prototype.add
45 | Svg.prototype.attr = SvgNode.prototype.attr
46 |
47 | Object.defineProperties(Svg.prototype, {
48 |
49 | width: { enumerable: true,
50 | set(width) { this.n.setAttribute('width', this._width = width) },
51 | get() {
52 | return (
53 | this._width !== undefined ? this._width :
54 | this._width = +this.n.getAttribute('width')
55 | )
56 | }
57 | },
58 |
59 | height: { enumerable: true,
60 | set(height) { this.n.setAttribute('height', this._height = height) },
61 | get() {
62 | return (
63 | this._height !== undefined ? this._height :
64 | this._height = +this.n.getAttribute('height')
65 | )
66 | }
67 | },
68 |
69 | viewBox: { enumerable: true,
70 | set({x=0, y=0, width=100, height=100}) {
71 | this._viewBox = {x, y, width, height}
72 | this.n.setAttribute('viewBox', `${x} ${y} ${width} ${height}`)
73 | },
74 | get() {
75 | if (!this._viewBox) {
76 | let v = this.n.getAttribute('viewBox').split(/\s+/)
77 | this._viewBox = {x:0, y:0, width: this.width, height: this.height}
78 | if (v.length == 4) {
79 | this._viewBox.x = +v[0]
80 | this._viewBox.y = +v[1]
81 | this._viewBox.width = +v[2]
82 | this._viewBox.height = +v[3]
83 | }
84 | }
85 | return this._viewBox
86 | }
87 | }
88 | })
89 |
--------------------------------------------------------------------------------
/docs/doc/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Documentation
4 | ---
5 |
6 | # Documentation
7 |
8 |
9 | ### [Language specification](spec.html)
10 |
11 | A slightly outdated document that will eventually be broken into
12 | smaller pieces.
13 |
14 |
15 | ## Architecture
16 |
17 | Code is structured into packages where a package can import other packages
18 | to make use of their code and data.
19 | A package is usually built from a number of source files, though source code
20 | need not be coming from files.
21 | Each package has its own namespace which holds all declarations, independently
22 | of where the declarations appear (i.e. source files.)
23 |
24 | 
25 |
26 | A package is built in a pipeline fashion, where each source file is
27 | concurrently processed.
28 |
29 | The parser pipeline converts UTF8 data into abstract syntax trees.
30 | It transforms bytes into tokens which are interpreted in a highly
31 | syntax-aware fashion, producing AST structures that represent the program
32 | in a lossless format.
33 |
34 | 
35 |
36 |
37 | The compiler pipeline operates at the granularity of functions and is mostly
38 | focused on Intermediate Representation (IR) code.
39 | An IR builder takes a function in AST form and builds a set of basic blocks
40 | in SSA form to represent the function at a essentially language-agnostic level.
41 | Optimizations are applied to the IR as a sequence of "passes", where some are
42 | always enabled and some are only enabled when "optimized" code is requested,
43 | trading time for code quality.
44 |
45 | 
46 |
47 | The IR builder is somewhat language-aware, as it converts AST into IR, but
48 | subsequent oprimization passes and code generation is language-agnostic and
49 | it would be possible to make use of this "back end" for other languages with
50 | similar runtime semantics to Co.
51 |
52 | An unresolved reference is an identifier which is unavailable or unknown at
53 | the time it is referenced. Usually this identifier is defined later in code,
54 | or in a separate source file. Anyhow, the compiler will stuff away functions
55 | which has unresolved references into a "wait set".
56 | Whenever an identifier is defined which causes a previously-unresolved
57 | function to become resolved (i.e. when all its references are known), that
58 | function is lifted out from the "wait set" and is compiled to completion.
59 |
60 | The parser and compiler pipeline makes use of some shared resources:
61 |
62 | 
63 |
64 | - Parser is a reusable resource that can parse source code from a list of bytes.
65 | - Universe represents built-in types and values and is shared amongst all
66 | parsers.
67 | - String set holds interned byte strings, allowing identifiers to internally
68 | be referenced by pointers rather than strings.
69 | - Type set holds interned user-type definitions, allowing types to internally
70 | be identified by pointers.
71 | - Type resolver is a reusable resource for resolving types from AST.
72 | It is allocated on a per-package basis.
73 | - IR builder is a resource that can either be provided with a parser
74 | allocation for online building of IR,
75 | or used separately to build IR from AST.
76 | - Package binder completes cross-references inside a package and manages
77 | importing of other packages. It can be run online by the parser,
78 | or as a separate step on AST.
79 |
80 |
81 |
82 | ## Topics
83 |
84 | [Intermediate representation (IR)](ir.html) — details on how code is
85 | represented internally and how SSA is used for optimizations.
86 |
87 | [Call stack](stack/) — discusses the call stack
88 |
89 | [Patterns](patterns.html) —
90 | Observations of common patterns in general programming and inspiration for Co
91 |
92 | [Chaitin-Briggs register allocation demo](chaitin/) —
93 | visualization of the Chaitin-Briggs graph-coloring register allocation
94 | algorithm.
95 |
--------------------------------------------------------------------------------
/docs/doc/ir.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: IR
4 | ---
5 |
6 | # Intermediate Representation (IR)
7 |
8 | When a program is compiled, it passes through a "pipeline"
9 | which can be visualized like this:
10 |
11 | `source text` —> `tokens` —> `AST` —> `IR code` —> `target code`
12 |
13 | First, source text is parsed into an Abstract Syntax tree. This is where
14 | syntactic transformations, scope resolution, variable resolution and
15 | type resolution happens, as well as most error checking.
16 | After some piece of source code has been successfully
17 | translated into AST, Intermediate Representation (just "IR" from here on) is
18 | built from the AST.
19 |
20 | Here's a short example, starting with source code:
21 |
22 | ```kt
23 | fun foo(x, y int) int {
24 | if x > 3 {
25 | y++
26 | }
27 | x + y
28 | }
29 | ```
30 |
31 | The following AST is built from parsing the `foo` function:
32 |
33 | ```txt
34 | (fun <(int, int)->int> foo ((x int) (y int))
35 | (block
36 | (if (GT x 3)
37 | (assign (y) INC)
38 | )
39 | (return (ADD x y))
40 | )
41 | )
42 | ```
43 |
44 | And here is the IR generated for that function's AST:
45 |
46 | ```go
47 | foo (int int)->int
48 | b0: // function's entry block
49 | v1 = LoadParam [0] // load parameter x
50 | v2 = LoadParam [1] // load parameter y
51 | v3 = i32Const [3] // load constant 3
52 | v4 = i32Gt_u v1 v3 // x > 3
53 | v5 = i32Const [1] // load constant 1
54 | if v4 —> b1 b2 // if ... then goto b1, else goto b2
55 |
56 | b1: <— b0 // "then" branch of "if"
57 | v6 = i32Add v2 v5 // y + 1
58 | cont —> b2 // unconditionally continue to block 2
59 |
60 | b2: <— b0, b1 // end "if" ("else" branch)
61 | v8 = Phi v2 v6 // note that y varies with entry branch
62 | v9 = i32Add v1 v8 // x + y
63 | ret v9 // return x from function
64 | ```
65 |
66 | We can observe a few things about this process:
67 |
68 | - The AST could be converted back to source code without loss of information,
69 | but the IR couldn't.
70 | - The IR is more verbose than the AST, but also a lot simpler,
71 | with just a single basic operation per line.
72 | - Branches are separated into blocks (aka "basic blocks") that connect to
73 | each other (`b0`, `b1`, etc are "blocks".)
74 | - The IR uses
75 | [SSA form](https://en.wikipedia.org/wiki/Static_single_assignment_form) which
76 | is why we don't see any traditional variable assignments, but instead just
77 | numbered variables (e.g. `v3`, `v10` etc.)
78 | - `x++` was simplified to `x = x + 1`
79 | - It looks similar to assembly language. This makes it easier to translate the
80 | IR to the target code.
81 |
82 |
83 | ## Internal constructs
84 |
85 | **Op** is an enum representing all basic operations (instructions).
86 | e.g. `i32Gt_u` for "compare two unsigned 32-bit integers with greater-then".
87 | There are a few special operations, like `Phi` which represents a SSA phi
88 | (branch merge point.) The set of operations closely matches the
89 | [instruction set of WebAssembly](https://webassembly.github.io/spec/core/syntax/instructions.html)
90 |
91 | **Value** is "a line of IR"; holds operation and operands in a
92 | Three-Address Code fashion. Uniquely numbered within a function.
93 |
94 | **Block** is basic block containing `Value`s.
95 | Contains links to predecessor blocks in `.preds` and to successors in `.succs`.
96 | Blocks forms the
97 | [Control Flow Graph](https://en.wikipedia.org/wiki/Control_flow_graph)
98 | of a function.
99 |
100 | **BlockKind** denotes what specific kind a block is; how a block exists.
101 | The `.control` property of the block controls the path taken from a block.
102 |
103 | | kind | control (x) | successors | notes
104 | | ---------- | -------------- | -------------- | --------
105 | | `Plain` | *(nil)* | next | e.g. cont/goto
106 | | `If` | boolean | then, else
107 | | `Ret` | memory | *(none)*
108 | | `First` | | next | used by lowering pass
109 |
110 | **Fun** represents a function and contains a list of all blocks that comprises
111 | the function. `Fun` also maintains a constant cache and handles value and block
112 | ID allocation.
113 |
114 | **IRBuilder** builds IR for a package on a per-function basis
115 |
--------------------------------------------------------------------------------
/docs/r/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsms/co/08634a87a6bc2d08f0cec58c798b9ef10e583536/docs/r/favicon.ico
--------------------------------------------------------------------------------
/docs/r/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/r/initdoc.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 | // analytics
4 | window.dataLayer = window.dataLayer || [];
5 | function g(){dataLayer.push(arguments);}
6 | g('js', new Date());
7 | g('config', 'UA-105091131-3');
8 |
9 | // helpers
10 | function $(q, e) {
11 | return (e || document).querySelector(q)
12 | }
13 | function $$(q, e) {
14 | return Array.prototype.slice.call((e || document).querySelectorAll(q))
15 | }
16 |
17 | // header anchors
18 | var L = 1;
19 | while (L < 5) {
20 | $$('.content h'+L+'[id]').forEach(function(e, i) {
21 | if (e.id) {
22 | var a = document.createElement('a')
23 | a.href = '#' + e.id
24 | a.innerHTML = e.innerHTML
25 | e.innerText = ''
26 | e.appendChild(a)
27 | }
28 | })
29 | L++
30 | }
31 |
32 | // add'l CSS styles
33 | var _extraStyleSheet
34 | function getExtraStyleSheet() {
35 | if (!_extraStyleSheet) {
36 | // Create the