about summary refs log tree commit diff stats
path: root/001help.cc
blob: 0625639d7473df475cc01462cce290f2272aa2b4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//: Everything this project/binary supports.
//: This should give you a sense for what to look forward to in later layers.

:(before "End Commandline Parsing")
if (argc <= 1 || is_equal(argv[1], "--help")) {
  // this is the functionality later layers will provide
  // currently no automated tests for commandline arg parsing
  cerr << "To load files and run 'main':\n"
       << "  mu file1.mu file2.mu ...\n"
       << "To run all tests:\n"
       << "  mu test\n"
       << "To load files and then run all tests:\n"
       << "  mu test file1.mu file2.mu ...\n"
       << "To load all files with a numeric prefix in a directory:\n"
       << "  mu directory1\n"
       << "You can test directories just like files.\n"
       << "To pass ingredients to a mu program, provide them after '--':\n"
       << "  mu file_or_dir1 file_or_dir2 ... -- ingredient1 ingredient2 ...\n"
       ;
  return 0;
}

//:: Helper function used by the above fragment of code (and later layers too,
//:: who knows?).
//: The :(code) directive appends function definitions to the end of the
//: project. Regardless of where functions are defined, we can call them
//: anywhere we like as long as we format the function header in a specific
//: way: put it all on a single line without indent, end the line with ') {'
//: and no trailing whitespace. As long as functions uniformly start this
//: way, our makefile contains a little command to automatically generate
//: declarations for them.
:(code)
bool is_equal(char* s, const char* lit) {
  return strncmp(s, lit, strlen(lit)) == 0;
}

// I'll throw some style conventions here for want of a better place for them.
// As a rule I hate style guides. Do what you want, that's my motto. But since
// we're dealing with C/C++, the one big thing we want to avoid is undefined
// behavior. If a compiler ever encounters undefined behavior it can make
// your program do anything it wants.
//
// For reference, my checklist of undefined behaviors to watch out for:
//   out-of-bounds access
//   uninitialized variables
//   use after free
//   dereferencing invalid pointers: null, a new of size 0, others
//
//   casting a large number to a type too small to hold it
//
//   integer overflow
//   division by zero and other undefined expressions
//   left-shift by negative count
//   shifting values by more than or equal to the number of bits they contain
//   bitwise operations on signed numbers
//
//   Converting pointers to types of different alignment requirements
//     T* -> void* -> T*: defined
//     T* -> U* -> T*: defined if non-function pointers and alignment requirements are same
//     function pointers may be cast to other function pointers
//
//       Casting a numeric value into a value that can't be represented by the target type (either directly or via static_cast)
//
// To guard against these, some conventions:
//
// 0. Initialize all primitive variables in functions and constructors.
//
// 1. Minimize use of pointers and pointer arithmetic. Avoid 'new' and
// 'delete' as far as possible. Rely on STL to perform memory management to
// avoid use-after-free issues (and memory leaks).
//
// 2. Avoid naked arrays to avoid out-of-bounds access. Never use operator[]
// except with map. Use at() with STL vectors and so on.
//
// 3. Valgrind all the things.
//
// 4. Avoid unsigned numbers. Not strictly an undefined-behavior issue, but
// the extra range doesn't matter, and it's one less confusing category of
// interaction gotchas to worry about.
//
// Corollary: don't use the size() method on containers, since it returns an
// unsigned and that'll cause warnings about mixing signed and unsigned,
// yadda-yadda. Instead use this macro below to perform an unsafe cast to
// signed. We'll just give up immediately if a container's ever too large.
:(before "End Includes")
#define SIZE(X) (assert((X).size() < (1LL<<(sizeof(long long int)*8-2))), static_cast<long long int>((X).size()))
//
// 5. Integer overflow is still impossible to guard against. Maybe after
// reading http://www.cs.utah.edu/~regehr/papers/overflow12.pdf

:(before "End Includes")
#include<assert.h>

#include<iostream>
using std::istream;
using std::ostream;
using std::iostream;
using std::cin;
using std::cout;
using std::cerr;

#include<cstring>
#include<string>
using std::string;