Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
da430cc
updated README
JTFulkerson Feb 11, 2026
0b7ffd6
Merge branch 'clause:main' into main
JTFulkerson Feb 11, 2026
4757202
L3 README with some inclass work on tests/check implementation
JTFulkerson Feb 13, 2026
b985268
I put the L3 readme in the wrong file so fixed that and wrote the L2 …
JTFulkerson Feb 13, 2026
c9cbe16
Merge branch 'clause:main' into main
JTFulkerson Feb 13, 2026
126028c
finished l1 and l0 readme content
JTFulkerson Feb 14, 2026
456ce24
in class work
JTFulkerson Feb 14, 2026
66d869e
Merge branch 'main' of github.com:JTFulkerson/471c
JTFulkerson Feb 14, 2026
34f5726
Merge branch 'main' into main
JTFulkerson Feb 18, 2026
dfc2ffe
Added class example but need to figure out how to get my stash. Pulle…
JTFulkerson Feb 18, 2026
331be98
Readme changes for testing
JTFulkerson Feb 18, 2026
0d90c17
Restored some of my old changes.
JTFulkerson Feb 19, 2026
f917ade
Restored previous stashed changes
JTFulkerson Feb 19, 2026
e5b9a18
Removed unnessesary checks on negative index and count values. Non ne…
JTFulkerson Feb 19, 2026
b3d2b5f
Merge branch 'clause:main' into main
JTFulkerson Feb 20, 2026
2c39f84
Merge branch 'clause:main' into main
JTFulkerson Feb 20, 2026
54016ba
Changed to use new pulled elimate letrec, wrote but have not tested l…
JTFulkerson Feb 20, 2026
a90bd8a
Merge branch 'clause:main' into main
JTFulkerson Feb 26, 2026
11d723f
Finished eliminating letrec, not passing all branch tests
JTFulkerson Feb 26, 2026
f405004
Merge branch 'clause:main' into main
JTFulkerson Feb 27, 2026
a2d246c
Merge branch 'clause:main' into main
JTFulkerson Feb 27, 2026
1ff63b5
Merge branch 'clause:main' into main
JTFulkerson Feb 27, 2026
e83aa3e
Fixed tests to have 100% branch coverage
JTFulkerson Feb 28, 2026
ab9d429
Merge pull request #1 from JTFulkerson/jtfulkerson/letrec-tests
JTFulkerson Feb 28, 2026
c6f5b30
Skipping parse tests
JTFulkerson Feb 28, 2026
85c43d7
added some test, should be at 100% code covereage now
JTFulkerson Feb 28, 2026
213df94
I think I finished the lark logic, need to finish parse and then can …
JTFulkerson Mar 5, 2026
c49323f
Removed the skip from all tests
JTFulkerson Mar 5, 2026
937f12d
Added most of parse logic, passing all provided tests but need to add…
JTFulkerson Mar 5, 2026
9f425dd
Added final test for branch coverage
JTFulkerson Mar 6, 2026
57d254a
Merge branch 'main' into main
JTFulkerson Mar 6, 2026
3036686
skipped test for optimizer
JTFulkerson Mar 6, 2026
4d66127
Added files for optimize and did first implementation of constant fol…
JTFulkerson Mar 12, 2026
470b5fb
Wrote constant propogation and broke helper functions out into util.py
JTFulkerson Mar 13, 2026
ce8e7ed
Merge branch 'clause:main' into main
JTFulkerson Mar 13, 2026
3e0fa1e
Dead code elimination implementation
JTFulkerson Mar 13, 2026
ddab7c5
Merge branch 'main' of github.com:JTFulkerson/471c
JTFulkerson Mar 13, 2026
cbd4dad
Commented out file
JTFulkerson Mar 13, 2026
8abe939
classwork with optimize implementation in main.py
JTFulkerson Mar 13, 2026
185f6fa
Cleaned up util helpers after class conversation
JTFulkerson Mar 13, 2026
0697662
added some uniquify logic and a few optimize tests
JTFulkerson Mar 13, 2026
f7323d3
went back to having optimize.py instead of matching arcitecture of pr…
JTFulkerson Mar 15, 2026
002418d
I updated constant folding and dead code elimination, working through…
JTFulkerson Mar 15, 2026
45e4434
omtimize tests
JTFulkerson Mar 15, 2026
ce5cedb
Had to fix some eliminate letrec errors...
JTFulkerson Mar 16, 2026
b3494b8
Finished unify and tests
JTFulkerson Mar 20, 2026
26f20e6
Added a comment to push a new change for codecov to hopefully run
JTFulkerson Mar 20, 2026
88a274f
Current class changes to cps
JTFulkerson Apr 3, 2026
0064c43
Uncommented tests and finished cps convert
JTFulkerson Apr 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Status

[![.github/workflows/ci.yml](https://github.com/clause/471c/actions/workflows/ci.yml/badge.svg)](https://github.com/clause/471c/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/clause/471c/branch/main/graph/badge.svg)](https://codecov.io/gh/clause/471c)
[![.github/workflows/ci.yml](https://github.com/JTFulkerson/471c/actions/workflows/ci.yml/badge.svg)](https://github.com/JTFulkerson/471c/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/JTFulkerson/471c/branch/main/graph/badge.svg)](https://codecov.io/gh/JTFulkerson/471c)

# Contributing

Expand Down
3 changes: 3 additions & 0 deletions packages/L0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
L0

L0 is now a procedure based language as compared to our previous expression and statement languages. Here, a program has a sequence of named procedures each containing its own parameters and a statement body. A statement can have copy, immediate, primative, branch, allocate, load, store, address, call, and hault. The main differences are that L0 organizes code into multiple named procedures whereas L1 had a single extry program with a statement body. L1 also uses abstract and apply for its functions where L0 replaces them with address and call removing a layer of abstraction. L0 also makes procedures ex plicity and predefined rather than in others where they were constructred functions at runtime.
3 changes: 3 additions & 0 deletions packages/L1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
L1

Now in L1 it is a statement based language with very explicit flow control. There exists a program which has parameters and a body, and the statements are similar to L2 and L3 with a few differences. We have copy, immediate, primative, branch, abstract, apply, allocate, load, store, and hault. The differences with L1 as compared to L2 and L3 is that L2 used nested terms as expressions while now L1 replaces all of those with sequential statements. Doing this makes flow control explicit as each statement has a then continuation, except for apply and hault. L1 also adds a copy ability to move values between identifiers, and hault to end the program. L1 removes the idea of let, reference, and begin.
3 changes: 3 additions & 0 deletions packages/L2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
L2

L2 has most of the same characteristics as L3 except letrec is missing. Functions, arithmetic, branching, and heap management all remain the same but not having letrec means that recursive bindings are not avalible.
180 changes: 180 additions & 0 deletions packages/L2/src/L2/constant_folding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
from functools import partial

from .syntax import (
Abstract,
Allocate,
Apply,
Begin,
Branch,
Immediate,
Let,
Load,
Primitive,
Reference,
Store,
Term,
)
from .util import (
Context,
extend_context_with_bindings,
recur_terms,
)


def _normalize_commutative_immediate_left(
operator: str,
left: Term,
right: Term,
) -> Primitive:
return Primitive(
operator=operator, # type: ignore[arg-type]
left=right,
right=left,
)


def constant_folding_term(
term: Term,
context: Context,
) -> Term:
recur = partial(constant_folding_term, context=context) # noqa: F841

match term:
case Let(bindings=bindings, body=body):
new_bindings, new_context = extend_context_with_bindings(bindings, context, recur)
return Let(
bindings=new_bindings,
body=constant_folding_term(body, new_context),
)

case Reference(name=name):
if name in context:
return context[name]
return term

case Abstract(parameters=parameters, body=body):
return Abstract(parameters=parameters, body=recur(body))

case Apply(target=target, arguments=arguments):
return Apply(
target=recur(target),
arguments=recur_terms(arguments, recur),
)

case Immediate(value=_value):
return term

case Primitive(operator=operator, left=left, right=right):
match operator:
case "+":
match recur(left), recur(right):
case Immediate(value=i1), Immediate(value=i2):
return Immediate(value=i1 + i2)

case Immediate(value=0), right:
return right

case [
Primitive(operator="+", left=Immediate(value=i1), right=left),
Primitive(operator="+", left=Immediate(value=i2), right=right),
]:
return Primitive(
operator="+",
left=Immediate(value=i1 + i2),
right=Primitive(
operator="+",
left=left,
right=right,
),
)

case left, Immediate() as right:
return _normalize_commutative_immediate_left("+", left, right)

# Coverage reports a synthetic exit arc on this fallback match arm.
# The arm is intentionally reachable and returns the non-folded primitive.
case left, right: # pragma: no branch
return Primitive(
operator="+",
left=left,
right=right,
)

case "-":
match recur(left), recur(right):
case Immediate(value=i1), Immediate(value=i2):
return Immediate(value=i1 - i2)

# Coverage reports a synthetic exit arc on this fallback match arm.
# The arm is intentionally reachable and returns the non-folded primitive.
case left, right: # pragma: no branch
return Primitive(operator="-", left=left, right=right)

# Coverage may report an extra arc on this literal case label under pattern matching.
# Runtime terms validated by the syntax model still follow normal folding logic below.
case "*": # pragma: no branch
match recur(left), recur(right):
case Immediate(value=i1), Immediate(value=i2):
return Immediate(value=i1 * i2)

case Immediate(value=0), _:
return Immediate(value=0)

case _, Immediate(value=0):
return Immediate(value=0)

case Immediate(value=1), right:
return right

case left, Immediate(value=1):
return left

case left, Immediate() as right:
return _normalize_commutative_immediate_left("*", left, right)

# Coverage reports a synthetic exit arc on this fallback match arm.
# The arm is intentionally reachable and returns the non-folded primitive.
case left, right: # pragma: no branch
return Primitive(operator="*", left=left, right=right)

case Branch(operator=operator, left=left, right=right, consequent=consequent, otherwise=otherwise):
folded_left = recur(left)
folded_right = recur(right)
folded_consequent = recur(consequent)
folded_otherwise = recur(otherwise)
match operator:
case "<":
match folded_left, folded_right:
case Immediate(value=i1), Immediate(value=i2):
return folded_consequent if i1 < i2 else folded_otherwise
case _:
pass
# Coverage may report an extra arc on this literal case label under pattern matching.
# Runtime terms validated by the syntax model use only "<" and "==".
case "==": # pragma: no branch
match folded_left, folded_right:
case Immediate(value=i1), Immediate(value=i2):
return folded_consequent if i1 == i2 else folded_otherwise
case _:
pass
return Branch(
operator=operator,
left=folded_left,
right=folded_right,
consequent=folded_consequent,
otherwise=folded_otherwise,
)

case Allocate(count=count):
return Allocate(count=count)

case Load(base=base, index=index):
return Load(base=recur(base), index=index)

case Store(base=base, index=index, value=value):
return Store(base=recur(base), index=index, value=recur(value))

# Coverage may report an extra structural arc for this match arm.
# Semantically this always returns the reconstructed Begin node.
case Begin(effects=effects, value=value): # pragma: no branch
return Begin(effects=recur_terms(effects, recur), value=recur(value))
88 changes: 88 additions & 0 deletions packages/L2/src/L2/constant_propogation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from functools import partial

from .syntax import (
Abstract,
Allocate,
Apply,
Begin,
Branch,
Immediate,
Let,
Load,
Primitive,
Reference,
Store,
Term,
)
from .util import (
Context,
extend_context_with_bindings,
recur_terms,
)


def constant_propogation_term(
term: Term,
context: Context,
) -> Term:
recur = partial(constant_propogation_term, context=context)

match term:
case Let(bindings=bindings, body=body):
new_bindings, new_context = extend_context_with_bindings(bindings, context, recur)
return Let(
bindings=new_bindings,
body=constant_propogation_term(body, new_context),
)

case Reference(name=name):
if name in context:
return context[name]
return term

case Abstract(parameters=parameters, body=body):
abstract_context = {name: value for name, value in context.items() if name not in parameters}
return Abstract(
parameters=parameters,
body=constant_propogation_term(body, abstract_context),
)

case Apply(target=target, arguments=arguments):
return Apply(
target=recur(target),
arguments=recur_terms(arguments, recur),
)

case Immediate(value=_value):
return term

case Primitive(operator=operator, left=left, right=right):
return Primitive(
operator=operator,
left=recur(left),
right=recur(right),
)

case Branch(operator=operator, left=left, right=right, consequent=consequent, otherwise=otherwise):
return Branch(
operator=operator,
left=recur(left),
right=recur(right),
consequent=recur(consequent),
otherwise=recur(otherwise),
)

case Allocate(count=count):
return Allocate(count=count)

case Load(base=base, index=index):
return Load(base=recur(base), index=index)

case Store(base=base, index=index, value=value):
return Store(base=recur(base), index=index, value=recur(value))

case Begin(effects=effects, value=value): # pragma: no branch
return Begin(
effects=recur_terms(effects, recur),
value=recur(value),
)
Loading