Test List
The following table lists all tests included in this documentation.
167 tests have been evaluated with version 0.5.0 of microcad.
Click on the test names to jump to file with the test or click the buttons to get the logs.
Automatic conversion of values when matching arguments
fn f( x: Scalar ) { _ = x; }
f(x=1);
f(x=[1]);
f(x=""); // error
f(""); // error
f(1.0);
f(1);
f([1.0]);
f([1]);
fn g( x: Integer ) { _ = x; }
g(x=1.0); // error
g(x=""); // error
g(""); // error
g(1.0); // error
g([1.0]); // error
g(1);
g([1]);
fn h( x: String ) { _ = x; }
h(x=1.0); // error
h(x="");
h(x=[""]);
h("");
h([""]);
h(1.0); // error
h([1.0]); // error
µcad Logo
Conditions
fn f(x: Integer) {
if x == 5 or x == 4 {
return "match";
} else if x > 0 and x < 4 {
return "no match";
} else {
return "invalid";
}
}
std::print(f(5)); // prints "match"
Ambiguous Look Up for properties/locals and operations
op scale() {}
sketch Sketch(scale: Scalar) { std::geo2d::Rect(size = scale * 40mm) }
Sketch(4.0);
Load an external module within MD test
mod external;
std::debug::assert(std::debug::is_valid("external::a"));
// file: external.µcad
pub const a =1;
Functions
// function definition
fn f() {}
// call
f();
// parameter
fn f(n: Scalar) {
// result value
n+1
}
use std::debug::*;
assert_eq([ f(1), 2 ]);
assert_eq([ f(4), 5 ]);
fn f(n: Scalar) {
return n+1;
}
use std::debug::*;
assert_eq([ f(1), 2 ]);
assert_eq([ f(4), 5 ]);
fn f(n: Scalar) {
if n > 3 {
n-1
} else {
n+1
}
}
use std::debug::*;
assert_eq([ f(1), 2 ]);
assert_eq([ f(4), 3 ]);
fn f(n: Scalar) {
if n > 3 {
return n-1;
}
n+1
}
use std::debug::*;
assert_eq([ f(1), 2 ]);
assert_eq([ f(4), 3 ]);
fn f(n: Scalar) { // error: not all paths return a value
if n > 3 {
n - 1
}
}
use std::debug::*;
assert_eq([ f(1), 2 ]);
assert_eq([ f(4), 3 ]);
Modules
mod a {
pub mod b {
pub mod c {
pub part M1() {}
}
}
pub part M2() {}
}
a::b::c::M1();
a::M2();
Scope tests
Scopes
a = 1;
use __builtin::debug::assert_valid;
use __builtin::debug::assert_invalid;
assert_valid("a");
assert_invalid("b");
assert_invalid("c");
{
assert_valid("a");
assert_invalid("b");
assert_invalid("c");
b = 2;
assert_valid("a");
assert_valid("b");
assert_invalid("c");
c = 3;
assert_valid("a");
assert_valid("b");
assert_valid("c");
};
assert_valid("a");
assert_invalid("b");
assert_invalid("c");
Usage of semicolon with Workbenches
use std::geo2d::Circle;
use std::ops::translate;
{ // op with body
Circle(radius = 5mm);
}.translate(y=[-34mm/2 , 34mm/2]);
use std::geo2d::Circle;
use std::ops::translate;
// op without body
Circle( radius = 5mm )
.translate(y = [-34mm/2 , 34mm/2]);
use std::geo2d::Circle;
use std::ops::translate;
{
Circle(radius = 5mm) // missing semicolon is ok.
}.translate(y=[-34mm/2 , 34mm/2]);
{}.std::ops::translate(x = 5mm);
use std::geo2d::Circle;
Circle(radius = 2mm) { Circle(radius = 1mm); } // parse_error: sketch with body
std::ops::translate(x = 3.0mm); // error: Cannot call operation without workpiece.
{}.std::ops::translate(x = 3.0mm);
use std::geo2d::Circle;
use std::ops::translate;
// group
{
Circle(radius = 1mm);
Circle(radius = 2mm);
}
use std::geo2d::Circle;
use std::ops::translate;
// assignment + group
a = {
Circle(radius = 1mm);
Circle(radius = 2mm);
};
Statement Usage
The following table shows which elements (rows) may occur in which Context (columns):
| Context/Element | Source File | Module | Initialization Code | Initializer | Workbench | Building code | Function code |
|---|---|---|---|---|---|---|---|
sketch, part, op | yes | yes | - | - | - | - | - |
mod | yes | yes | - | - | - | - | - |
fn | yes | yes | - | - | - | - | - |
init | - | - | yes | - | yes | - | - |
use | yes | yes | yes | yes | yes | yes | yes |
pub use | yes | yes | - | - | - | - | - |
return | - | - | - | - | - | - | yes |
if | yes | - | - | - | yes | yes | yes |
@input | - | - | - | - | yes | ?yes? | - |
x = 1 | yes | yes | - | yes | yes | yes | yes |
const | yes | yes | - | - | - | - | - |
prop | - | - | - | - | yes | - | - |
| expression | yes | - | - | - | yes | yes | yes |
| Test | Test | Test | Test | Test | Test | Test |
Source
sketch F() {} F();
mod m {}
fn f() {} f();
init() {} // error
use std;
pub use std;
return 1; // error
if std::math::PI == 3 { __builtin::geo2d::Circle(radius=1mm); }
const B = 1;
pub p = 1;
a = 1;
prop a = 1; // error
1 + 2;
__builtin::geo2d::Circle(radius=1mm);
Module
mod k {
sketch F() {}
}
mod k {
mod m {}
}
mod k {
fn f() {}
}
mod k {
init() { } // error
}
mod k {
use std::geo2d;
}
mod k {
pub use std::geo2d;
}
mod k {
return 1; // error
}
mod k {
if std::math::PI == 3 { __builtin::geo2d::Circle(radius=1); } // error
}
mod k {
const B = 1;
}
mod k {
pub p = 1;
}
mod k {
a = 1; // error
}
mod k {
prop a = 1; // error
}
mod k {
1 + 2; // error
}
mod k {
__builtin::geo2d::Circle(radius=1mm); // error
}
Pre-Init
sketch K() {
sketch F() {} // error
init(l:Length) {} } K();
sketch K() {
mod m {} // error
init(l:Length) {} } K();
sketch K() {
fn f() {} f(); // error
init(l:Length) {} } K();
sketch K(x: Length) {
init() { x=1; }
init(l:Length) {} } K();
sketch K() {
use std;
init(l:Length) {} } K();
sketch K() {
pub use std; // error
init(l:Length) {} } K();
sketch K() {
return 1; // error
init(l:Length) {} } K();
sketch K() {
if std::math::PI == 3 { } // error
init(l:Length) {} } K();
sketch K() {
const B = 1;
init(l:Length) {} } K();
sketch K() {
pub p = 1; // error
init(l:Length) {} } K();
sketch K() {
a = 1; // error
init(l:Length) {} } K();
sketch K() {
prop a = 1; // error
init(l:Length) {} } K();
sketch K() {
1 + 2; // error
init(l:Length) {} } K();
sketch K() {
__builtin::geo2d::Circle(radius=1mm); // error
init(l:Length) {} }
Init
sketch K() { init(l:Length) {
sketch F() {} // error
} } K(1cm);
sketch K() { init(l:Length) {
mod m {} // error
} } K(1cm);
sketch K() { init(l:Length) {
fn f() {} // error
} } K(1cm);
sketch K() { init(l:Length) {
init() {} // error
} } K(1cm);
sketch K() { init(l:Length) {
use std;
} } K(1cm);
sketch K() { init(l:Length) {
pub use std; // error
} } K(1cm);
sketch K() { init(l:Length) {
return l; // error
} } K(1cm);
sketch K() { init(l:Length) {
if std::math::PI == l { } // error
} } K(1cm);
sketch K() { init(l:Length) {
const B = l; // error
} } K(1cm);
sketch K() { init(l:Length) {
pub a = l; // error
} } K(1cm);
sketch K() { init(l:Length) {
a = l;
} } K(1cm);
sketch K() { init(l:Length) {
prop a = l; // error
} } K(1cm);
sketch K() { init(l:Length) {
l + 2; // error
} } K(1cm);
sketch K() { init(l:Length) {
__builtin::geo2d::Circle(radius=l);
} } K(1cm);
Workbench
sketch K() {
sketch F() {} F(); // error
} K();
sketch K() {
mod m {} // error
} K();
sketch K() {
fn f() {} f();
} K();
sketch K(x: Scalar) {
init() { x = 1; }
} K();
sketch K() {
use std;
} K();
sketch K() {
pub use std; // error
} K();
sketch K() {
return 1; // error
} K();
sketch K() {
if std::math::PI == 3 { }
} K();
sketch K() {
@input; // error: Input marker is not allowed here.
} K();
sketch K() {
const B = 1;
} K();
sketch K() {
a = 1;
} K();
sketch K() {
prop a = 1;
} K();
sketch K() {
pub a = 1; // error
} K();
sketch K() {
1 + 2;
} K();
sketch K() {
__builtin::geo2d::Circle(radius=1mm);
} K();
Body
{
sketch F() {} // error
}
{
mod m {} // error
}
{
fn f() {} f(); // error
}
{
init() {} // error
}
{
use std;
}
{
pub use std; // error
}
{
return 1; // error
}
{
if std::math::PI == 3 { }
}
{
@input
}
{
const B = 1; // error
}
{
pub p = 1; // error
}
{
a = 1;
}
{
prop a = 1; // error
}
{
1 + 2;
}
{
__builtin::geo2d::Circle(radius=1mm);
}
Function
fn f() {
sketch S() {} // error
} f();
fn f() {
mod m {} // error
} f();
fn f() {
fn f() {} // error
} f();
fn f() {
init() {} // error
} f();
fn f() {
use std;
} f();
fn f() {
pub use std; // error
} f();
fn f() {
return 1;
} f();
fn f() {
if std::math::PI == 3 { __builtin::geo2d::Circle(radius=1); }
} f();
fn f() {
const B = 1; // error
} f();
fn f() {
pub p = 1; // error
} f();
fn f() {
a = 1;
} f();
fn f() {
prop a = 1; // error
} f();
fn f() {
1 + 2;
} f();
fn f() {
__builtin::geo2d::Circle(radius=1mm);
} f();
Symbols
mod foo {
pub const A = 1mm;
}
fn foo() -> Length { // error: Ambiguous identifiers
foo::A
}
foo();
Tuple Argument Matching
The concept behind named tuple argument matching is to allow functions to accept subsets of parameters in a bundle. This makes it easy to pre-configure parts of arguments:
// Function with three parameters: x, y, and z
fn f( x: Length, y: Length, z: Length ) {}
// Since we do not want to change x and y in the following statements,
// we prepare a tuple named plane:
plane = (x=1cm, y=2cm);
// Then we pass plane to f() three times with different z values
f( plane, z=3cm);
f( plane, z=6cm);
f( plane, z=9cm);
The same function can be called in various ways using named tuples:
fn f( x: Length, y: Length, z: Length ) {}
// Every parameter given by name
f( x=1cm, y=2cm, z=3cm);
// Parameters given by named tuple
f( (x=1cm, y=2cm, z=3cm) );
// Parameters given by named tuple variable
p = (x=1cm, y=2cm, z=3cm);
f( p );
// Parameters given by named tuple and a single value
f( (x=1cm, y=2cm), z=3cm );
f( y=2cm, (x=1cm, z=3cm) );
// Parameters given by named tuple variable and a single value
q = (x=1cm, y=2cm);
f( q, z=3cm );
Tuple Multiplicity
Another example uses an array of tuples and produces the same output:
r = std::geo2d::Rect(width = 2mm, height = 2mm);
r.std::ops::translate([(x=-4mm, y=-4mm), (x=-4mm, y=4mm), (x=4mm, y=-4mm), (x=4mm, y=4mm)]);
Use statement tests
// use debug from `std/module.µcad`
use std::debug::assert;
use std::debug::assert_valid;
use std::debug::assert_invalid;
assert(true);
// use all symbols from std::debug for test checks
use std::debug::*;
// use symbol `circle` in file `geo2d.µcad`
use std::geo2d::Circle;
assert_valid("Circle");
// use all symbols in file `geo3d.µcad`
use std::geo3d::*;
assert_valid("Sphere");
assert_valid("Cube");
// alias `Circle` in `std/geo2d/mod.µcad` into `foo`
use std::geo2d::Circle as foo;
assert_valid("foo");
// use print from `std/module.µcad`
use std::print;
assert_valid("print");
print("Hello");
// public use operation from `std/module.µcad`
pub use std::ops;
assert_valid("ops");
part MyPart() {
Circle(radius=1);
Sphere(radius=1);
}
assert_valid("MyPart");
use std::geo2d::*;
use Rect as Cap;
Cap(width=1mm,height=1mm);
// use symbol `circle` in file `geo2d.µcad`
use std::geo2d::Circle;
// use all symbols in file `geo3d.µcad`
use std::geo3d::*;
// alias `bar` in `std/text/foo.µcad` into `baz`
use std::math::abs as baz;
// use print from `std/module.µcad`
use std::print;
// public use operation from `std/module.µcad`
pub use std::ops;
// use debug from `std/module.µcad`
use std::debug;
debug::assert(true);
part MyPart3d() { Sphere(radius=1mm); }
sketch MySketch2d() { Circle(radius=1mm); }
x = MySketch2d();
y = MyPart3d();
z = baz(-1.0);
fn f() {
use std::math::abs;
x = abs(-1.0);
return x;
}
f();
fn f() {
use std::math::*;
x = abs(-1.0);
return x;
}
f();
mod my {
mod name {
pub mod space {
pub use std::geo2d::*;
}
}
pub use name::space::*;
}
my::Circle(radius = 4mm);
my::Rect(size = 40mm);
Value Declarations
| Keyword(s) | Context | Description | Example |
|---|---|---|---|
| - | source, workbench, function | local value | a=1 |
| - | init | property (if in building plan), else local value | a=1 |
prop | workbench | model property | prop a=1 |
const | module | private module value | const a=1; |
pub, (pub const) | module | public module value | pub a=1;, pub const a=1; |
use | module, source, workbench, function, init | private usage | use std::geo3d; |
pub use | module, source | public usage | pub use std::geo3d; |
fn | module, source, workbench | private function | fn() {} |
pub fn | module, source | public function | pub fn() {} |
use std::debug::*;
mod module {
use std::debug::*;
// private module variable
const value = 1;
// public module variable
pub pub_value = 2;
pub mod pub_sub_module {
// pre-init code
use std::debug::*;
// private module variable
const value = 3;
// public module variable
pub pub_value = 4;
// private workbench
sketch PrivateWorkbench() {}
// public workbench
pub sketch Workbench(param = 5) {
const sketch_local = 6;
init(alt_param = 7) {
init_local = 8;
assert_eq([value, 3]);
assert_eq([pub_value, 4]);
assert_invalid("param");
assert_eq([sketch_local, 6]);
assert_eq([alt_param, 7]);
assert_eq([init_local, 8]);
}
// property of sketch
prop property = 9;
// post init code
assert_eq([value, 3]);
assert_eq([pub_value, 4]);
assert_eq([param, 5]);
assert_eq([sketch_local, 6]);
assert_invalid("alt_param");
assert_invalid("init_local");
assert_eq([property, 9]);
function();
}
fn function(fn_param = 10) {
assert_eq([value, 3]);
assert_eq([pub_value, 4]);
assert_invalid("param");
// assert_invalid(Workbench);
assert_eq([fn_param, 10]);
return 0;
}
}
pub fn function(fn_param = 11) {
assert_eq([value, 1]);
assert_eq([pub_value, 2]);
assert_invalid("pub_sub_module::value");
assert_eq([pub_sub_module::pub_value, 4]);
assert_invalid("Workbench");
assert_invalid("PrivateWorkbench");
assert_eq([fn_param, 11]);
return 0;
}
}
// source file code
assert_invalid("module::value");
assert_eq([module::pub_value, 2]);
assert_invalid("module::pub_sub_module::value");
assert_eq([module::pub_sub_module::pub_value, 4]);
assert_eq([module::pub_sub_module::Workbench(p=5).property, 9]);
assert_invalid("module::pub_sub_module::PrivateWorkbench");
assert_eq([module::function(), 0]);
Visibility
mod my {
mod mod_private {
pub const_public = 1;
const const_private = 1;
}
pub mod mod_public {
pub const_public = 1;
const const_private = 1;
}
}
use __builtin::debug::assert_valid;
use __builtin::debug::assert_invalid;
assert_valid("my::mod_public::const_public");
assert_invalid("my::mod_public::const_private");
assert_invalid("my::private_public::const_public");
assert_invalid("my::private_public::const_private");