Compare commits

...

4 Commits

Author SHA1 Message Date
Ondřej Hruška 2800b8cab2
life is now better 4 years ago
Ondřej Hruška 54ff5fbce9
Merge branch 'nat-master' into master 4 years ago
Ondřej Hruška 8d10fa406d
Minor "else" improvements 4 years ago
Ondřej Hruška f61dc00291
add GOL example 4 years ago
  1. 3
      README.md
  2. 6
      crsn/crsn-sexp/src/error.rs
  3. 5
      crsn/crsn-sexp/src/lib.rs
  4. 14
      crsn/src/asm/instr/flatten.rs
  5. 12
      crsn/src/asm/instr/op.rs
  6. 242
      examples/life.csn
  7. 19
      examples/test_cond.csn

@ -98,8 +98,7 @@ These keywords (among others) are used in conditional branches to specify flag t
- `nem`, `nempty` … Not empty
- `eof` … EOF
- `neof` … Not EOF
- `true`, `always`, `else` … Always true
- `false`, `never` … Always false
- `else` … Always true, may be used in the last branch
# Syntax

@ -19,6 +19,12 @@ pub struct SourcePosition {
pub index: u32,
}
impl fmt::Display for SourcePosition {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}:{}", self.line, self.column)
}
}
/// Since errors are the uncommon case, they're boxed. This keeps the size of
/// structs down, which helps performance in the common case.
///

@ -331,10 +331,11 @@ fn parse_sexp(s: &str, pos: &mut usize) -> ERes<Sexp> {
//trace!("parse_sexp {}", pos);
zspace(s, pos)?;
let (c, _) = peek(s, *pos)?;
let pos0 = *pos;
let r = if c == '(' {
Ok(Sexp::List(parse_list(s, pos)?, spos(s, *pos)))
Ok(Sexp::List(parse_list(s, pos)?, spos(s, pos0)))
} else {
Ok(Sexp::Atom(parse_atom(s, pos)?, spos(s, *pos)))
Ok(Sexp::Atom(parse_atom(s, pos)?, spos(s, pos0)))
};
zspace(s, pos)?;
r

@ -50,7 +50,7 @@ impl Flatten for InstrWithBranches {
}
if cnt != branch_count - 1 && cond == Cond::True {
warn!("\"Else\" conditional used in non-final branch at {}:{}", branch.pos().line, branch.pos().column);
warn!("\"Else\" conditional used in non-final branch at {}", branch.pos());
}
let next_lbl = if cnt == branch_count - 1 {
@ -68,11 +68,13 @@ impl Flatten for InstrWithBranches {
// optimization for single-branch conditionals with a single instruction
ops.push(Op { cond: Some(cond), pos: pos.clone(), kind: flattened.remove(0).kind });
} else {
ops.push(Op {
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
pos: pos.clone(),
cond: Some(!cond),
});
if cond != Cond::True { // evoid emiting `op.never`
ops.push(Op {
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
pos: pos.clone(),
cond: Some(!cond),
});
}
ops.extend(flattened);
}

@ -50,11 +50,15 @@ impl OpTrait for Op {
OpKind::Ext(op) => op.to_sexp()
};
// TODO rewrite to be more readable?
if let Some(cond) = self.cond {
if let Sexp::List(items, _) = &mut se {
if let Some(Sexp::Atom(Atom::S(s), _)) = &mut items.get_mut(0) {
s.push('.');
s.push_str(&cond.to_string());
// "true" is used for "else" branches, it has no effect - just omit it
if cond != Cond::True {
if let Sexp::List(items, _) = &mut se {
if let Some(Sexp::Atom(Atom::S(s), _)) = &mut items.get_mut(0) {
s.push('.');
s.push_str(&cond.to_string());
}
}
}
}

@ -0,0 +1,242 @@
(
; simple GOL with screen and a buffer + DRAWING!!!
; Middle-click to payse or resume
; (hold the button until paused - there is a sleep between generations and checking buttons)
;
; When paused, draw with left (white) and right (black) mouse buttons
;
; Resume by clicking middle again.
(def GENERATION_MS 200)
; Real pixel size
(sc-init 400 400)
; Upscaling factor (bug pixels)
(sc-opt SCREEN_UPSCALE 10)
; Number of big pixels
(def W 40)
(def H 40)
; !!! If you change size, also update the following constants.
; Compile-time math is not implemented yet.
(def XMAX 39) ; W-1
(def YMAX 39) ; H-1
(def NCELLS 1600) ; W*H
; --- end of config ---
(sc-opt SCREEN_AUTO_BLIT 0)
(sc-erase 0) ; all black
(sym ng g15)
(mkbf ng NCELLS)
; one glider
(bfwr @ng 1 1)
(bfwr @ng 42 1)
(bfwr @ng 80 1)
(bfwr @ng 81 1)
(bfwr @ng 82 1)
; another glider
(bfwr @ng 16 1)
(bfwr @ng 55 1)
(bfwr @ng 95 1)
(bfwr @ng 96 1)
(bfwr @ng 97 1)
(def LBTN 0)
(def RBTN 1)
(def MBTN 2)
(:loop)
(sc-poll)
; Drawing
(sc-mbtn _ MBTN
(nz?
(:release)
(sc-poll)
(mslp 10)
(sc-mbtn _ MBTN (nz? (j :release)))
(:mousing)
(sc-poll)
(mslp 10)
(ld r3 -1)
(sc-mbtn _ LBTN)
(ld.nz r3 1)
(sc-mbtn _ RBTN)
(ld.nz r3 0)
(tst r3 (nneg?
(sc-mouse r0 r1)
(tst r3)
(sc-wr.nz r0 r1 #ffffff)
(sc-wr.z r0 r1 #000000)
(sc-blit)
(mul r1 W)
(add r0 r1)
(ld8 r3:8 r3)
(bfwr @ng r0 r3)
))
(sc-mbtn _ MBTN
(z? (j :mousing)))
(:release2)
(sc-poll)
(mslp 10)
(sc-mbtn _ MBTN (nz? (j :release2)))
)
)
(call Display)
(sc-blit)
(mslp GENERATION_MS)
(j :loop)
(proc CountNeighbors x y
(sym xx r4)
(sym yy r5)
(sym i r6)
(sym count r7)
; yeah this sucks. it's correct, though
(:a)
(add yy y -1 (neg? (j :d)))
(add xx x -1 (neg? (j :b)))
(mul i yy W)
(add i xx)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:b)
(mul i yy W)
(add i x)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:c)
(add xx x 1)
(cmp xx W (ge? (j :d)))
(mul i yy W)
(add i xx)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:d)
(add xx x -1 (neg? (j :f)))
(mul i y W)
(add i xx)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
; there is no E
(:f)
(add xx x 1)
(cmp xx W (ge? (j :g)))
(mul i y W)
(add i xx)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:g)
(add yy y 1)
(cmp yy H (ge? (j :end)))
(add xx x -1 (neg? (j :h)))
(mul i yy W)
(add i xx)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:h)
(add yy y 1)
(cmp yy H (ge? (j :end)))
(mul i yy W)
(add i x)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:i)
(add yy y 1)
(cmp yy H (ge? (j :end)))
(add xx x 1)
(cmp xx W (ge? (j :end)))
(mul i yy W)
(add i xx)
(bfrd r0 @ng i)
(and r0 0xFF (nz? (inc count)))
(:end)
(ret count)
)
(proc Display
; display and calc next gen
(sym x r4)
(sym y r5)
(sym i r6)
(:next)
; The lower byte contains 0 or 1
; the second byte will be filled with the next gen
(bfrd r0 @ng i)
; Show this gen
(and r0 0xFF
(nz? (sc-wr x y 0xffffff))
(z? (sc-wr x y 0x000000)))
(call CountNeighbors x y)
; stay: 2,3
; die: >3
; born: 3
(cmp res0 2
(eq? (ld8 r0:8 r0)) ; stasis
(ne?
(tst r0
(z?
(cmp res0 3 (eq? (ld8 r0:8 1))) ; birth
)
(nz?
(cmp res0 3 (eq? (ld8 r0:8 1))) ; stay alive
)
)
)
)
(bfwr @ng i r0)
(inc i)
(inc x)
(cmp x W
(ne? (j :next)))
(ld x 0)
(inc y)
(cmp y H
(eq? (j :next2)))
(j :next)
; Shift all by 8 to the right (generation shift)
(:next2)
(dec i)
(bfrd r0 @ng i)
(lsr r0 8)
(bfwr @ng i r0)
(tst i)
(j.nz :next2)
(ret)
)
)

@ -1,4 +1,23 @@
(
; test else
(cmp 0 5
(eq? (fault))
(else? (ld r0 15))
(lt? (fault)) ; This should produce a warning
)
(cmp 15 r0
(ne? (fault "else did not run")))
(ld r0 0)
(cmp 0 5
(lt? (nop))
(else? (fault "fallthrough to else"))
)
;
(ld r8 0)
(ld r0 1

Loading…
Cancel
Save