WARNING: You are connected to the internet! Click HERE to learn why this could be dangerous.
Cancel Process/Logout Welcome
You are not logged into the account that needs to sign these transactions. Please log out and try again.
Verify/Sign transaction(s)
Enter the transaction script (given to you by the website) to convert it into a readable format that can be verified manually.
Are you ready to sign transaction(s)?
×
IMPORTANT: Please check to make sure that the field highlighted in white is correct and accurate. The bitcoin value should be the purchase price for the transaction minus the commission. Check the bitcoin address to make sure it's an address you control. If the address is incorrect or you lose your passphrase for that wallet, you may not be able to recover the funds after you have signed and broadcast the transaction. The other field is the market's commission.
IMPORTANT: Please check to make sure that the field highlighted in white is correct and accurate. The bitcoin value should be the purchase price for the transaction minus the commission. Check the bitcoin address to make sure it's an address you control. If the address is incorrect or you lose your passphrase for that wallet, you may not be able to recover the funds after you have signed and broadcast the transaction. The other field is the market's commission.
Transaction skipped.
Transaction successfully signed.
| Amount | Address |
Transaction #
Notice: If the transaction's outputs are not correct, please contact support with the subject line "Problem with Transaction #".
Are you sure you would like to skip this transaction?
Are you sure you would like to skip the rest of your transactions?
The following transactions have been successfully signed: Transaction(s)
The following transactions have not been signed: Transaction(s)


Shelter Helper is a platform for shelters to safely and securely keep track of clients and get them the resources they need.
Find Out MoreWe found that homeless shelters in Seattle have concerns regarding the efficiency of the client check-in process, client information privacy, and accessing additional social services. To address these concerns, we worked with social workers and shelter volunteers to design a web page, Shelter Helper, that addresses their needs and pain points.
See FeaturesSearch for services tailored to your client needs.
Easily add a new client to the database.
Organize your clients in one secure location.
Find statistics specific to your shelter.
Task 1: Add a new client by uploading a preexisting intake form
Task 2: Do a personalized searching looking for the SNAP service for a client
Additional Pages
We conducted interviews with a shelter volunteer, a shelter director, and a professor of social work.
We developed a desktop application to improve intake processes and connection to other services.
We tested our paper prototype on 3 shelter volunteers who had to complete our two tasks.
We revised our paper prototype and made a digital mockup that combined our design patterns.


SENDIT
Logout
Profile
Parcel
Home
Parcel Orders
create parcel
Calculating distance......
Parcel Order Form
x
Sender Address:
Delivery Location:
Weight:
Weight Metric:
Create Parcel
Cancel Parcel Dialogue
x
dismiss
cancel
Change Destination Form
x
New Destination
Submit
successful


INTELLIGENT CRIME MANAGEMENT SYSTEM
Crime Types Criteria
Select Crime Location
Choose...
Bukan-Sidi
Student Village
Post Office Area
Lavista
Nas ST. Poly
Project Quarters
Lafia East
Modern Market
Lafia Township Stadium
Workers Village
Tundun Gwandara
U.A.C Road
Dunama
Inec Office
Tahiti Lodge Area
Old Tomato Market
Government Residential Area
Lafia Emirs Palace
Millionaire Quarters
Open University
Day of Week
Choose...
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Time of Day
Choose...
1:00 am
2:00 am
3:00 am
4:00 am
5:00 am
6:00 am
7:00 am
8:00 am
9:00 am
10:00 am
11:00 am
12:00 pm
1:00 pm
2:00 pm
3:00 pm
4:00 pm
5:00 pm
6:00 pm
7:00 pm
8:00 pm
9:00 pm
10:00 pm
11:00 pm
0:00 am
Month
Choose...
January
February
March
April
May
June
July
August
September
October
November
December
Copyright © 2018. All rights reserved.


@* * Copyright 2021 HM Revenue & Customs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *@ @import models.HowBecameOwnerModel @import uk.gov.hmrc.play.views.html.{helpers => govHelpers} @import views.html.helpers._ @import play.api.Application @import config.ApplicationConfig @(howBecameOwnerForm: Form[HowBecameOwnerModel])(implicit request: Request[_], messages: Messages, application: Application, applicationConfig: ApplicationConfig) @main_template(title = Messages("calc.howBecameOwner.question")) { @Messages("calc.base.back") @errorSummary(howBecameOwnerForm, "gainedBy")


Healthchecks is open-source, and is licensed under the BSD 3-clause license.
As an alternative to using the hosted service at https://healthchecks.io, you have the option to host a Healthchecks instance yourself.
The building blocks are:
You can set up a development environment in a Python virtual environment on your local system to develop a new feature, write a new integration or test a bugfix.
The following instructions assume you are using a Debian-based OS.
Install dependencies:
$ sudo apt-get update
$ sudo apt-get install -y gcc python3-dev python3-venv
Prepare directory for project code and virtualenv. Feel free to use a different location:
$ mkdir -p ~/webapps
$ cd ~/webapps
Prepare virtual environment (with virtualenv you get pip, we'll use it soon to install requirements):
$ python3 -m venv hc-venv
$ source hc-venv/bin/activate
Check out project code:
$ git clone https://github.com/healthchecks/healthchecks.git
Install requirements (Django, ...) into virtualenv:
$ pip install wheel
$ pip install -r healthchecks/requirements.txt
Create database tables and a superuser account:
$ cd ~/webapps/healthchecks
$ ./manage.py migrate
$ ./manage.py createsuperuser
With the default configuration, Healthchecks stores data in a SQLite file
hc.sqlite
in the project directory (~/webapps/healthchecks/
).
Run tests:
$ ./manage.py test
Run development server:
$ ./manage.py runserver
From another shell, run the sendalerts
management command, responsible for
sending out notifications:
$ ./manage.py sendalerts
At this point, the site should now be running at http://localhost:8000
.
Healthchecks comes with Django's administration panel where you can manually view and modify user accounts, projects, checks, integrations etc. To access it, if you haven't already, create a superuser account:
$ ./manage.py createsuperuser
Then, log into the site using the superuser credentials. Once logged in, click on the "Account" dropdown in top navigation, and select "Site Administration".
Healthchecks needs SMTP credentials to be able to send emails: login links, monitoring notifications, monthly reports.
Specify SMTP credentials using the EMAIL_HOST
, EMAIL_PORT
, EMAIL_HOST_USER
,
EMAIL_HOST_PASSWORD
, and EMAIL_USE_TLS
environment variables. Example:
EMAIL_HOST=my-smtp-server-here.com
EMAIL_PORT=587
EMAIL_HOST_USER=my-username
EMAIL_HOST_PASSWORD=mypassword
EMAIL_USE_TLS = True
You can read more about handling outbound email in the Django documentation, Sending Email section.
Healthchecks comes with a smtpd
management command, which starts up a
SMTP listener service. With the command running, you can ping your
checks by sending email messages.
Start the SMTP listener on port 2525:
$ ./manage.py smtpd --port 2525
Send a test email:
$ curl --url 'smtp://<IP_ADDRESS>:2525' \
--mail-from<EMAIL_ADDRESS>\
--mail-rcpt<EMAIL_ADDRESS>\
-F '='
The sendalerts
management command continuously polls the database for any checks
changing state, and sends out notifications as needed.
When sendalerts
is not running, the Healthchecks instance will not send out any
alerts.
Within an activated virtualenv, run the sendalerts
command like so:
$ ./manage.py sendalerts
In a production setup, make sure the sendalerts
command can survive
server restarts.
With time and use the Healthchecks database will grow in size. You may decide to prune old data: inactive user accounts, old checks not assigned to users, old records of outgoing email messages. There are separate Django management commands for each task:
Remove old records of sent notifications. For each check, remove notifications that are older than the oldest stored ping for the corresponding check.
$ ./manage.py prunenotifications
Remove inactive user accounts:
$ ./manage.py pruneusers
Remove old records from the api_tokenbucket
table. The TokenBucket
model is used for rate-limiting login attempts and similar operations.
Any records older than one day can be safely removed.
$ ./manage.py prunetokenbucket
Remove old records from the api_flip
table. The Flip objects are used to track
status changes of checks, and to calculate downtime statistics month by month.
Flip objects from more than 3 months ago are not used and can be safely removed.
$ ./manage.py pruneflips
When you first try these commands on your data, it is a good idea to test them on a copy of your database, and not on the live system.
In a production setup, you will want to run these commands regularly, as well as have regular, automatic database backups set up.
Get the source code.
See Configuration for a list of configuration options.


--- title: EARTH DAY SPRING GARDEN TOUR date: 2016-04-07 00:00:00 -06:00 categories: - spring subtitle: layout: events event-image: earth-day-spring-garden-tour.jpg event-dates: SATURDAY, APRIL 22 @ 10AM-NOON event-location: Red Butte Garden button-type: register tickets-link: https://55218.blackbaudhosting.com/55218/Earth-Day-Spring-Garden-Tour member-sale-date: N/A public-sale-date: N/A member-cost: Free public-cost: Garden Admission event-notes: tickets-button: '' ---
Join us for an exploration of what's blooming throughout the Garden. Walk with one of our Garden Guides to take an intimate look at the Garden and see how it has changed. Wear comfortable clothes and walking shoes. Meet in the Visitor Center Courtyard.
REGISTRATION REQUIRED


The nuclear receptor PPARgamma - bigger than fat.
Abstract
Work reported over the past year has provided insights into the mechanisms whereby ligand activation of the nuclear receptor peroxisome proliferator-activated receptor gamma (PPARgamma) regulates systemic glucose and lipid homeostasis. PPARgamma has also been implicated recently in the biology of monocytes and in cell-cycle regulation and cancer. Polyunsaturated fatty acids and eicosanoids bind and activate PPARgamma, suggesting that these lipids may serve as hormonal regulators of a variety of biological processes.


{% extends 'base.html' %} {% block content %}
Days: {% for daygroupday in daygroup.daygroupday_set.all %} {{ daygroupday.day.number }} {% endfor %}
Edit | Delete
Back to All Day Groups.


Keith Dailey
e-mail<EMAIL_ADDRESS>Office: 326 Avery Hall
Office Hours: TBA
This
summer, I am teaching Math 203, Contemporary
Mathematics.
I
am a first year graduate student and teaching assistant in the Department of Mathematics at the University of Nebraska-Lincoln.
I earned a B.A.
in Mathematics from Grand Valley State University
in April 2003.
The above picture was used in a paper about
elliptic curves that I wrote as an undergraduate.
On a more personal note, I got married this last June to Katrina (formerly)
Tessin. We were married in our hometown of Hemlock, MI, and honeymooned at the
Porcupine Mountains in Michigan's Upper Peninsula. Eventually, I hope to put
some pictures from our trip on this page.
This is a picture of Katrina and our kitty Persephone in our new apartment.


| Invoice No. | Purchase order No. & Date: |
| State: | Date: |
| State Code: | Vehicle No: |
| CGST | SGST |
|---|
| No: | Name of the Product | Unit Price | Quantity | Amount | Taxable Value | Rate | Amount | Rate | Amount | Total | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Delete (-) |
| CGST | SGST |
|---|
| No: | Name of the Product | Unit Price | Quantity | Amount | Taxable Value | Rate | Amount | Rate | Amount | Total |
|---|---|---|---|---|---|---|---|---|---|---|
| Total |
|
Total Amount (in words):
|
|
|
Bank Details
Bank Account Number:
IFSC Code:
|
Common Seal |
DECLARATIONCertified that all the particulars shown in the above Tax Invoice are true and correct.
Authorized Signatory
|


---
title: HTML Escape | UnEscape Online | Developer Tools
layout: post
---
{% include common-meta %}
{{ page.title }}
{% include theme-css %}
{% include ie-fixes %}
{% include theme-header %}
{% include theme-sidebar %}
{% include theme-footer %}
{% include theme-bottom-js %}


Brian
&
Kiwana
MAY 24
th
, 2015
Your browser does not support the audio element.
Your cordially invited to help celebrate the union of:
Brian G. Mc Conduit & Kiwana M. Craft
MAY 24
th
, 2015
SAVE THE DATE
LOCATION TO BE ANNOUNCED
CONSIDER THIS YOUR FORMAL INVITATION


HEAD ======= <<<<<<< HEAD >>>>>>> f57e6ae079db3192a5701f6dcbe3223465f12be8
You can search treatments and doctors with required keywords


{{ conversation?.mainPost?.postContent?.title }}
Edit Post
{{ conversation?.mainPost?.postContent?.abstract }}
{{ tag.name }}
{{ conversation?.mainPost?.postCreator?.name }}
Modified:
{{ conversation?.mainPost?.dtLastModified | date }}
Comments
({{ conversation?.replyPost.length + conversation?.postCount }})
0">


--- layout: archive title: Zulip Chat Archive permalink: /stream/113488-general/topic/Map.20from.20sum.20in.20standard.20lib.3F.html ---
Is a function similar to this one (and a notation for it) available in the standard library?
def map_from_sum {A B C : Type} (f : A → C) (g : B → C) : (A ⊕ B) → C | (sum.inl a) := f a | (sum.inr b) := g b
Thanks, Benedikt
You're really here to check that your students aren't cheating in your Lean course, right? ;-)
I was expecting to lay my hands on that function at once, but I can't immediately find it.
or.elim : ∀ {a b c : Prop}, a ∨ b → (a → c) → (b → c) → c
but I couldn't spot sum.elim
oh found it, it's in data.sum
ha ha, I didn't even know that file existed.
import data.sum #check @sum.elim /- sum.elim : Π {α : Type u_1} {β : Type u_2} {γ : Sort u_3}, (α → γ) → (β → γ) → α ⊕ β → γ -/
Nice, I didn't know this existed either. Non-dependent eliminators are frequently more convenient, I wish Lean would generate them automatically.
I was surprised that suggest
didn't help:
import tactic import data.sum def map_from_sum {A B C : Type} (f : A → C) (g : B → C) : (A ⊕ B) → C := by suggest /- There are no applicable declarations state: A B C : Type, f : A → C, g : B → C ⊢ A ⊕ B → C -/
Might be because it's data not a prop?
Ah, that makes sense. This reminds me of how we couldn't use cc
on your "random types" challenge.
Thanks a lot for your answers.
I tried hard to find empty.elim
(or another map of type empty -> C), but have not been successful. Is such a map pre-defined?
empty.elim
does exist (in mathlib, logic.basic
, one of the very first imports). There's also empty.rec
and empty.rec_on
in core.
It's just logic.basic
, not data.logic.basic
.
I was also surprised suggest
didn't find this. Maybe suggest
shouldn't filter out Sort *
declarations? @Scott Morrison
Last updated: Apr 24 2020 at 19:02 UTC


{% extends "_base/base_of_landing_page.html" %} {% load i18n %} {% block html_class %} class="full-height"{% endblock html_class %} {% block content %} {% blocktrans %}
Aqsa is simple, but free software which have some powerful functionality even compare some commercial software.
{% endblocktrans %} {% endblock content %} {% block landing_features %}{% trans "Just few clicks for import statement from your bank and make sum of income/expense reports." %}
* {% trans "Available bank at this time is only Sberbank." %}
{% trans "The edit mode will save your time for categorize your income and expenses. Very easy." %}
{% trans "You can use tags and categories. Categories will allow you to make a report of income/expense balance by category." %}
{% trans "Do not worry about to make mistakes when you add/remove transactions. Keep your data just in case making back up files and easily import them to new account." %}


The Material Design Lite (MDL) data-table component is an enhanced version of the standard HTML

. A data-table consists of rows and columns of well-formatted data, presented with appropriate user interaction capabilities.
Tables are a ubiquitous feature of most user interfaces, regardless of a site's content or function. Their design and use is therefore an important factor in the overall user experience. See the data-table component's Material Design specifications page for details.
The available row/column/cell types in a data-table are mostly self-formatting; that is, once the data-table is defined, the individual cells require very little specific attention. For example, the rows exhibit shading behavior on mouseover and selection, numeric values are automatically formatted by default, and the addition of a single class makes the table rows individually or collectively selectable. This makes the data-table component convenient and easy to code for the developer, as well as attractive and intuitive for the user.
1. Code a

element. Include

and

elements to hold the title and data rows, respectively.

2. Add one or more MDL classes, separated by spaces, to the table using the class
attribute.

2. Inside the

, code exactly one table row

containing one table header cell
for each column, and include the desired text in the header cells. To ensure proper header alignment, add the "non-numeric" MDL class to the header cell of text-only columns. (Data cells are formatted as numeric by default.)

Name
Age
ID Number

3. Inside the

, code one table row

for each data row and one table data cell
for each column in the row. As with the header cells, add the "non-numeric" MDL class to text-only data cells to ensure proper alignment.

Name
Age
ID Number

Don Aubrey
25
49021

Sophia Carson
32
10258

Steve Moreno
29
12359

The data-table component is ready for use.
A data-table with a "master" select checkbox and individual row select checkboxes.

Material
Quantity
Unit price

Acrylic (Transparent)
250
$2.90

Plywood (Birch)
50
$1.25

Laminate (Gold on Blue)
10
$12.35

A data-table without select checkboxes containing mostly text data.

Name
Nickname
Age
Living?

John Lennon
The smart one
40
No

Paul McCartney
The cute one
73
Yes

George Harrison
The shy one
58
No

Ringo Starr
The funny one
74
Yes

The MDL CSS classes apply various predefined visual and behavioral enhancements to the data-table. The table below lists the available classes and their effects.
| MDL class | Effect | Remarks |
|---|---|---|
mdl-data-table |
Defines table as an MDL component | Required on table element |
mdl-js-data-table |
Assigns basic MDL behavior to table | Required on table element |
mdl-data-table--selectable |
Applies all/individual selectable behavior (checkboxes) | Optional; goes on table element |
mdl-data-table__cell--non-numeric |
Applies text formatting to data cell | Optional; goes on both table header and table data cells |
| (none) | Applies numeric formatting to header or data cell (default) |


Three Poets
Home
Longfellow
Poe
Withman
Welcome
This site is a tribute to three poets.
Henry Wadsworth Longfellow
Edgar Allan Poe
Walt Whitman
© 2019 Nobody at all |
Contact


ALERT_CHILDREN
Alert only for the Children of the Group
See Also
NotificationCompat.GROUP_ALERT_CHILDREN


|
| | CPU () |
| | Default constructor. More...
|
| |
|
| CPU (const CPU &in_CPU) |
| |
|
| CPU (const CPU *in_CPU) |
| |
|
| ~CPU () |
| | Destructor.
|
| |
| UInt16 | DumpFlagRegister () const |
| | Dump the flag register. More...
|
| |
| std::vector< UInt8 > | DumpMemory () const |
| | Dump the CPU memory. More...
|
| |
| UInt16 | DumpProgramCounter () const |
| | Dump the program counter. More...
|
| |
| UInt16 | DumpRegister (const UInt8 in_RegID) const |
| | Dump the value contained in a register. More...
|
| |
| std::vector< UInt16 > | DumpRegisters () const |
| | Dump the CPU registers. More...
|
| |
| UInt16 | DumpStackPointer () const |
| | Dump the stack pointer. More...
|
| |
| unsigned | Init (std::vector< UInt8 > &&in_ROMData) |
| | Initialize the central processing unit. More...
|
| |
|
void | Reset () |
| | Restore the central processing unit at its pre-initialized state.
|
| |
| void | SetFlagRegister (const UInt16 in_Value) |
| | Set the value of the flag register. More...
|
| |
| void | SetFlag (const UInt16 in_Value) |
| | Set a flag within the flag register. More...
|
| |
| void | UnsetFlag (const UInt16 in_Value) |
| | Unset a flag within the flag register. More...
|
| |
| UInt8 | SetProgramCounter (const UInt16 in_Value) |
| | Set the value of the PC. More...
|
| |
| UInt8 | SetRegister (const UInt8 in_RegID, const UInt16 in_Value) |
| | Set the value of a register. More...
|
| |
| UInt8 | SetStackPointer (const UInt16 in_Value) |
| | Set the value of the SP. More...
|
| |
|
void | StepBack () |
| | Make the PC go back to the previous instruction.
|
| |
| void | UpdateController (SDL_KeyboardEvent &in_Event) |
| | Update a controller memory mapped IO port. More...
|
| |
| std::vector< Instruction > | FetchBasicBlock () |
| | Fetch a contiguous block of sequential instruction. More...
|
| |
| Instruction | FetchInstruction () |
| | Read the current instruction and its operands as pointed by the PC. Note that it increases the PC by 4 i.e. to the next instruction. More...
|
| |
| std::vector< UInt8 > | FetchPalette (const UInt16 in_Address) |
| | Read a number of bytes from memory which corresponds to a palette data. More...
|
| |
|
void | FetchRegistersValues (UInt16 &out_X, UInt16 &out_Y) const |
| | Extract the values contained within the registers whose addresses are in the byte pointed by the PC.
|
| |
| std::vector< UInt8 > | FetchSprite (const UInt16 in_Addr, const UInt16 in_Width, const UInt16 in_Height) const |
| | Read a number of bytes from memory which corresponds to a sprite data. More...
|
| |
| UInt8 | Load (const UInt16 in_Address, UInt16 &out_Value) const |
| | Load a value from memory. More...
|
| |
| UInt8 | Store (const UInt16 in_Address, const UInt16 in_Value) |
| | Store a value in memory. More...
|
| |
| UInt8 | Pop (UInt16 &out_Value) |
| | Pop a value from the stack of the emulator and decrement the SP by 2. More...
|
| |
| UInt8 | Push (UInt16 in_Val) |
| | Push a value on the stack and increment the SP by 2. More...
|
| |
| UInt8 | PushPC () |
| | Push the PC on the stack and increment the SP by 2. More...
|
| |
|
void | SetSignZeroFlag (UInt16 in_Result) |
| | Set the sign flag if the bit[15] of the result is lit and set the zero flag if the result is zero.
|
| |
|
void | SetCarryOverflowFlag (UInt16 in_Op1, UInt16 in_Op2) |
| |
|
void | SetCarryOverflowFlagAdd (UInt16 in_Op1, UInt16 in_Op2) |
| |
|
void | SetCarryOverflowFlagDiv (UInt16 in_Op1, UInt16 in_Op2) |
| |
|
void | SetCarryOverflowFlagMul (UInt16 in_Op1, UInt16 in_Op2) |
| |
|
void | SetCarryOverflowFlagSub (UInt16 in_Op1, UInt16 in_Op2) |
| |
Emulates the Central Processing Unit (CPU)
- Author
- Felix-Antoine Ouellet


These are values that the client needs to supply to identify itself. These are
| Required? | Default | Description | |
| accessTokenUri | Y | ServiceUri + /token | The address which the client should use for getting the access token. Normally this is constructed from the serviceUri and should only be set explicitly by the server administrator if needed. |
| assetUri | Y | ServiceUri + /getcert | The address from which the client will get the certificate. Normally this is constructed from the serviceUri and should only be set explicitly by the server administrator if needed. |
| authorizeUri | Y | ServiceUri + /authorize | The address which the client should use for authorization. Normally this is constructed from the serviceUri and should only be set explicitly by the server administrator if needed. |
| callbackUri | Y | N/A | The redirect address to which the user is sent after authorization. Note that this can be reset at runtime before the call is made, should you want to customize it per user. |
| deviceAuthorizationUri | Y | ServiceUri + /device_authorization | The address which the client should use for initiating the device authorization flow (RFC 8628). Normally this is constructed from the serviceUri and should only be set explicitly by the server administrator if needed. |
| enableAssetCleanup | N | false | Whether the service will automatically remove old assets in the store. |
| id | Y | N/A | The unique identifier generated by the server during the registration process. |
| keypairLifetime | N | 0 | The maximum age, in seconds, for the client-side generated keypair to be cached. Keypair caching reduces key generation load on heavily used clients by re-using a keypair across OAuth sessions. This functionality should only be used if the keypair remains secured in the OAuth client and is not externally exposed. It affects the keypair used to generate certificate requests and is not the same as the OAuth keypair created at registration. Setting the value to zero forces the client to generate a new keypair with each request. This keypair is stored in the asset for the request. |
| lifetime | N | 43200 | The requested lifetime in seconds this certificate should last. The service will always apply its own policies to any request. The default is 12 hours. |
| maxAssetLifetime | N | 2592000 (one calendar month in seconds) | The maximum age, in seconds, that an asset may be in the store. This only applies if the cleanup facility is enabled and the OAuth version is 1.0a. In the OAuth 2.0 version this is ignored, since cleanup of old assets is determined by the lifetime of the refresh token. |
| secret | Y | N/A | The secret that is given to the client at registration. This should be cut and pasted with no blanks or other characters into the configuration file. Note that the server does not store this! It will only store a hash of it so if you lose it, you must re-register. |
| serviceUri | Y | N/A | The address of the service this client uses. |
| showRedirectPage | N | false | Whether to pause the exchange to show a page containing the redirect URL and the private key. Set this to true to enable. Generally this is rather useful in debugging but should not be enabled in production systems. Note that this only applies to OAuth 1.0a since the protocol under OAuth 2.0 is different. |
| skin | N | N/A | The skin that the site will display for this client. This lets OA4MP servers mimic the look and feel of the client site. You should contact the server administration to set this up with you if you are interested. |
| userInfoUri | Y | ServiceUri + /userinfo | The address from which the client will get user information. Normally this is constructed from the serviceUri and should only be set explicitly by the server administrator if needed. |
| wellKnownUri | Y | N/A | The address of the well-known page for the server. |
If any of the required parameters are omitted, then an exception will be raised. The certificate lifetime may be omitted. If present, it will be processed in accordance with the service's cert lifetime policies and there is no requirement that the requested lifetime be honored.
<config> <client> <callbackUri>http://client.example.org/client2/ready</callbackUri> <secret>bwM9YgIMM4oMeOTZdJLyp8shgfuzrwWHxS401pEx8w2_BOk5ip46zJL_bsTj2bU5iuS7QsiGmze44pA2k3MhYuPGOkSSMpUEkpXI9KZqY_OVGOI8B3JYj8q0ZWP80hkmshwzYQiHOz5IJW7KZpMOQSKVG5lbmP0_iSwPim74WwH9akuc_3pocIntA5OfVtRKl0LCAz1WkXUSbF5sH6-xx8SWPJvaU0rc95jmxXqUxib3iXwYgheo1yyrvK4RHsStppZD9RmcwgyhLxvgUDap-23tm</secret> <serviceUri>https://server.example.org/oauth2</serviceUri> <id>myproxy:delegation,2011:/client/c43d987fedbf7c3258973fdedc8</id> <fileStore path="/path/to/asset/store/"> <assetStore/> </fileStore> <enableAssetCleanup>true</enableAssetCleanup> </client> </config>
The secret that is sent to the server is put in without linebreaks. The keypair lifetime is omitted which means that the client will take the default (currently a new keypair will be generated once every 24 hours.) There is no maxAssetLifetime parameter here since that is not needed in OAuth 2.0-based clients. However, asset cleanup is still enabled.


Welcome to Chapter 5 of the "Implementing a language with LLVM" tutorial. Parts 1-4 described the implementation of the simple Kaleidoscope language and included support for generating LLVM IR, followed by optimizations and a JIT compiler. Unfortunately, as presented, Kaleidoscope is mostly useless: it has no control flow other than call and return. This means that you can't have conditional branches in the code, significantly limiting its power. In this episode of "build that compiler", we'll extend Kaleidoscope to have an if/then/else expression plus a simple 'for' loop.
Extending Kaleidoscope to support if/then/else is quite straightforward. It basically requires adding support for this "new" concept to the lexer, parser, AST, and LLVM code emitter. This example is nice, because it shows how easy it is to "grow" a language over time, incrementally extending it as new ideas are discovered.
Before we get going on "how" we add this extension, lets talk about "what" we want. The basic idea is that we want to be able to write this sort of thing:
def fib(x) if x < 3 then 1 else fib(x-1)+fib(x-2);
In Kaleidoscope, every construct is an expression: there are no statements. As such, the if/then/else expression needs to return a value like any other. Since we're using a mostly functional form, we'll have it evaluate its conditional, then return the 'then' or 'else' value based on how the condition was resolved. This is very similar to the C "?:" expression.
The semantics of the if/then/else expression is that it evaluates the condition to a boolean equality value: 0.0 is considered to be false and everything else is considered to be true. If the condition is true, the first subexpression is evaluated and returned, if the condition is false, the second subexpression is evaluated and returned. Since Kaleidoscope allows side-effects, this behavior is important to nail down.
Now that we know what we "want", lets break this down into its constituent pieces.
The lexer extensions are straightforward. First we add new enum values for the relevant tokens:
// control tok_if = -6, tok_then = -7, tok_else = -8,
Once we have that, we recognize the new keywords in the lexer. This is pretty simple stuff:
... if (IdentifierStr == "def") return tok_def; if (IdentifierStr == "extern") return tok_extern; if (IdentifierStr == "if") return tok_if; if (IdentifierStr == "then") return tok_then; if (IdentifierStr == "else") return tok_else; return tok_identifier;
To represent the new expression we add a new AST node for it:
/// IfExprAST - Expression class for if/then/else. class IfExprAST : public ExprAST { ExprAST *Cond, *Then, *Else; public: IfExprAST(ExprAST *cond, ExprAST *then, ExprAST *_else) : Cond(cond), Then(then), Else(_else) {} virtual Value *Codegen(); };
The AST node just has pointers to the various subexpressions.
Now that we have the relevant tokens coming from the lexer and we have the AST node to build, our parsing logic is relatively straightforward. First we define a new parsing function:
/// ifexpr ::= 'if' expression 'then' expression 'else' expression static ExprAST *ParseIfExpr() { getNextToken(); // eat the if. // condition. ExprAST *Cond = ParseExpression(); if (!Cond) return 0; if (CurTok != tok_then) return Error("expected then"); getNextToken(); // eat the then ExprAST *Then = ParseExpression(); if (Then == 0) return 0; if (CurTok != tok_else) return Error("expected else"); getNextToken(); ExprAST *Else = ParseExpression(); if (!Else) return 0; return new IfExprAST(Cond, Then, Else); }
Next we hook it up as a primary expression:
static ExprAST *ParsePrimary() { switch (CurTok) { default: return Error("unknown token when expecting an expression"); case tok_identifier: return ParseIdentifierExpr(); case tok_number: return ParseNumberExpr(); case '(': return ParseParenExpr(); case tok_if: return ParseIfExpr(); } }
Now that we have it parsing and building the AST, the final piece is adding LLVM code generation support. This is the most interesting part of the if/then/else example, because this is where it starts to introduce new concepts. All of the code above has been thoroughly described in previous chapters.
To motivate the code we want to produce, lets take a look at a simple example. Consider:
extern foo(); extern bar(); def baz(x) if x then foo() else bar();
If you disable optimizations, the code you'll (soon) get from Kaleidoscope looks like this:
declare double @foo() declare double @bar() define double @baz(double %x) { entry: %ifcond = fcmp one double %x, 0.000000e+00 br i1 %ifcond, label %then, label %else then: ; preds = %entry %calltmp = call double @foo() br label %ifcont else: ; preds = %entry %calltmp1 = call double @bar() br label %ifcont ifcont: ; preds = %else, %then %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] ret double %iftmp }
To visualize the control flow graph, you can use a nifty feature of the LLVM 'opt' tool. If you put this LLVM IR into "t.ll" and run "llvm-as < t.ll | opt -analyze -view-cfg", a window will pop up and you'll see this graph:
Another way to get this is to call "F->viewCFG()" or "F->viewCFGOnly()" (where F is a "Function*") either by inserting actual calls into the code and recompiling or by calling these in the debugger. LLVM has many nice features for visualizing various graphs.
Getting back to the generated code, it is fairly simple: the entry block evaluates the conditional expression ("x" in our case here) and compares the result to 0.0 with the "fcmp one" instruction ('one' is "Ordered and Not Equal"). Based on the result of this expression, the code jumps to either the "then" or "else" blocks, which contain the expressions for the true/false cases.
Once the then/else blocks are finished executing, they both branch back to the 'ifcont' block to execute the code that happens after the if/then/else. In this case the only thing left to do is to return to the caller of the function. The question then becomes: how does the code know which expression to return?
The answer to this question involves an important SSA operation: the Phi operation. If you're not familiar with SSA, the wikipedia article is a good introduction and there are various other introductions to it available on your favorite search engine. The short version is that "execution" of the Phi operation requires "remembering" which block control came from. The Phi operation takes on the value corresponding to the input control block. In this case, if control comes in from the "then" block, it gets the value of "calltmp". If control comes from the "else" block, it gets the value of "calltmp1".
At this point, you are probably starting to think "Oh no! This means my simple and elegant front-end will have to start generating SSA form in order to use LLVM!". Fortunately, this is not the case, and we strongly advise not implementing an SSA construction algorithm in your front-end unless there is an amazingly good reason to do so. In practice, there are two sorts of values that float around in code written for your average imperative programming language that might need Phi nodes:
In Chapter 7 of this tutorial ("mutable variables"), we'll talk about #1 in depth. For now, just believe me that you don't need SSA construction to handle this case. For #2, you have the choice of using the techniques that we will describe for #1, or you can insert Phi nodes directly, if convenient. In this case, it is really really easy to generate the Phi node, so we choose to do it directly.
Okay, enough of the motivation and overview, lets generate code!
In order to generate code for this, we implement the Codegen method for IfExprAST:
Value *IfExprAST::Codegen() { Value *CondV = Cond->Codegen(); if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE(CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond");
This code is straightforward and similar to what we saw before. We emit the expression for the condition, then compare that value to zero to get a truth value as a 1-bit (bool) value.
Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB);
This code creates the basic blocks that are related to the if/then/else statement, and correspond directly to the blocks in the example above. The first line gets the current Function object that is being built. It gets this by asking the builder for the current BasicBlock, and asking that block for its "parent" (the function it is currently embedded into).
Once it has that, it creates three blocks. Note that it passes "TheFunction" into the constructor for the "then" block. This causes the constructor to automatically insert the new block into the end of the specified function. The other two blocks are created, but aren't yet inserted into the function.
Once the blocks are created, we can emit the conditional branch that chooses between them. Note that creating new blocks does not implicitly affect the IRBuilder, so it is still inserting into the block that the condition went into. Also note that it is creating a branch to the "then" block and the "else" block, even though the "else" block isn't inserted into the function yet. This is all ok: it is the standard way that LLVM supports forward references.
// Emit then value. Builder.SetInsertPoint(ThenBB); Value *ThenV = Then->Codegen(); if (ThenV == 0) return 0; Builder.CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. ThenBB = Builder.GetInsertBlock();
After the conditional branch is inserted, we move the builder to start inserting into the "then" block. Strictly speaking, this call moves the insertion point to be at the end of the specified block. However, since the "then" block is empty, it also starts out by inserting at the beginning of the block. :)
Once the insertion point is set, we recursively codegen the "then" expression from the AST. To finish off the "then" block, we create an unconditional branch to the merge block. One interesting (and very important) aspect of the LLVM IR is that it requires all basic blocks to be "terminated" with a control flow instruction such as return or branch. This means that all control flow, including fall throughs must be made explicit in the LLVM IR. If you violate this rule, the verifier will emit an error.
The final line here is quite subtle, but is very important. The basic issue is that when we create the Phi node in the merge block, we need to set up the block/value pairs that indicate how the Phi will work. Importantly, the Phi node expects to have an entry for each predecessor of the block in the CFG. Why then, are we getting the current block when we just set it to ThenBB 5 lines above? The problem is that the "Then" expression may actually itself change the block that the Builder is emitting into if, for example, it contains a nested "if/then/else" expression. Because calling Codegen recursively could arbitrarily change the notion of the current block, we are required to get an up-to-date value for code that will set up the Phi node.
// Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); Builder.SetInsertPoint(ElseBB); Value *ElseV = Else->Codegen(); if (ElseV == 0) return 0; Builder.CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. ElseBB = Builder.GetInsertBlock();
Code generation for the 'else' block is basically identical to codegen for the 'then' block. The only significant difference is the first line, which adds the 'else' block to the function. Recall previously that the 'else' block was created, but not added to the function. Now that the 'then' and 'else' blocks are emitted, we can finish up with the merge code:
// Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); return PN; }
The first two lines here are now familiar: the first adds the "merge" block to the Function object (it was previously floating, like the else block above). The second block changes the insertion point so that newly created code will go into the "merge" block. Once that is done, we need to create the PHI node and set up the block/value pairs for the PHI.
Finally, the CodeGen function returns the phi node as the value computed by the if/then/else expression. In our example above, this returned value will feed into the code for the top-level function, which will create the return instruction.
Overall, we now have the ability to execute conditional code in Kaleidoscope. With this extension, Kaleidoscope is a fairly complete language that can calculate a wide variety of numeric functions. Next up we'll add another useful expression that is familiar from non-functional languages...
Now that we know how to add basic control flow constructs to the language, we have the tools to add more powerful things. Lets add something more aggressive, a 'for' expression:
extern putchard(char) def printstar(n) for i = 1, i < n, 1.0 in putchard(42); # ascii 42 = '*' # print 100 '*' characters printstar(100);
This expression defines a new variable ("i" in this case) which iterates from a starting value, while the condition ("i < n" in this case) is true, incrementing by an optional step value ("1.0" in this case). If the step value is omitted, it defaults to 1.0. While the loop is true, it executes its body expression. Because we don't have anything better to return, we'll just define the loop as always returning 0.0. In the future when we have mutable variables, it will get more useful.
As before, lets talk about the changes that we need to Kaleidoscope to support this.
The lexer extensions are the same sort of thing as for if/then/else:
... in enum Token ... // control tok_if = -6, tok_then = -7, tok_else = -8, tok_for = -9, tok_in = -10 ... in gettok ... if (IdentifierStr == "def") return tok_def; if (IdentifierStr == "extern") return tok_extern; if (IdentifierStr == "if") return tok_if; if (IdentifierStr == "then") return tok_then; if (IdentifierStr == "else") return tok_else; if (IdentifierStr == "for") return tok_for; if (IdentifierStr == "in") return tok_in; return tok_identifier;
The AST node is just as simple. It basically boils down to capturing the variable name and the constituent expressions in the node.
/// ForExprAST - Expression class for for/in. class ForExprAST : public ExprAST { std::string VarName; ExprAST *Start, *End, *Step, *Body; public: ForExprAST(const std::string &varname, ExprAST *start, ExprAST *end, ExprAST *step, ExprAST *body) : VarName(varname), Start(start), End(end), Step(step), Body(body) {} virtual Value *Codegen(); };
The parser code is also fairly standard. The only interesting thing here is handling of the optional step value. The parser code handles it by checking to see if the second comma is present. If not, it sets the step value to null in the AST node:
/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression static ExprAST *ParseForExpr() { getNextToken(); // eat the for. if (CurTok != tok_identifier) return Error("expected identifier after for"); std::string IdName = IdentifierStr; getNextToken(); // eat identifier. if (CurTok != '=') return Error("expected '=' after for"); getNextToken(); // eat '='. ExprAST *Start = ParseExpression(); if (Start == 0) return 0; if (CurTok != ',') return Error("expected ',' after for start value"); getNextToken(); ExprAST *End = ParseExpression(); if (End == 0) return 0; // The step value is optional. ExprAST *Step = 0; if (CurTok == ',') { getNextToken(); Step = ParseExpression(); if (Step == 0) return 0; } if (CurTok != tok_in) return Error("expected 'in' after for"); getNextToken(); // eat 'in'. ExprAST *Body = ParseExpression(); if (Body == 0) return 0; return new ForExprAST(IdName, Start, End, Step, Body); }
Now we get to the good part: the LLVM IR we want to generate for this thing. With the simple example above, we get this LLVM IR (note that this dump is generated with optimizations disabled for clarity):
declare double @putchard(double) define double @printstar(double %n) { entry: ; initial value = 1.0 (inlined into phi) br label %loop loop: ; preds = %loop, %entry %i = phi double [ 1.000000e+00, %entry ], [ %nextvar, %loop ] ; body %calltmp = call double @putchard(double 4.200000e+01) ; increment %nextvar = fadd double %i, 1.000000e+00 ; termination test %cmptmp = fcmp ult double %i, %n %booltmp = uitofp i1 %cmptmp to double %loopcond = fcmp one double %booltmp, 0.000000e+00 br i1 %loopcond, label %loop, label %afterloop afterloop: ; preds = %loop ; loop always returns 0.0 ret double 0.000000e+00 }
This loop contains all the same constructs we saw before: a phi node, several expressions, and some basic blocks. Lets see how this fits together.
The first part of Codegen is very simple: we just output the start expression for the loop value:
Value *ForExprAST::Codegen() { // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->Codegen(); if (StartVal == 0) return 0;
With this out of the way, the next step is to set up the LLVM basic block for the start of the loop body. In the case above, the whole loop body is one block, but remember that the body code itself could consist of multiple blocks (e.g. if it contains an if/then/else or a for/in expression).
// Make the new basic block for the loop header, inserting after current // block. Function *TheFunction = Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = Builder.GetInsertBlock(); BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB);
This code is similar to what we saw for if/then/else. Because we will need it to create the Phi node, we remember the block that falls through into the loop. Once we have that, we create the actual block that starts the loop and create an unconditional branch for the fall-through between the two blocks.
// Start insertion in LoopBB. Builder.SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, VarName.c_str()); Variable->addIncoming(StartVal, PreheaderBB);
Now that the "preheader" for the loop is set up, we switch to emitting code for the loop body. To begin with, we move the insertion point and create the PHI node for the loop induction variable. Since we already know the incoming value for the starting value, we add it to the Phi node. Note that the Phi will eventually get a second value for the backedge, but we can't set it up yet (because it doesn't exist!).
// Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. Value *OldVal = NamedValues[VarName]; NamedValues[VarName] = Variable; // Emit the body of the loop. This, like any other expr, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (Body->Codegen() == 0) return 0;
Now the code starts to get more interesting. Our 'for' loop introduces a new variable to the symbol table. This means that our symbol table can now contain either function arguments or loop variables. To handle this, before we codegen the body of the loop, we add the loop variable as the current value for its name. Note that it is possible that there is a variable of the same name in the outer scope. It would be easy to make this an error (emit an error and return null if there is already an entry for VarName) but we choose to allow shadowing of variables. In order to handle this correctly, we remember the Value that we are potentially shadowing in OldVal (which will be null if there is no shadowed variable).
Once the loop variable is set into the symbol table, the code recursively codegen's the body. This allows the body to use the loop variable: any references to it will naturally find it in the symbol table.
// Emit the step value. Value *StepVal; if (Step) { StepVal = Step->Codegen(); if (StepVal == 0) return 0; } else { // If not specified, use 1.0. StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); } Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar");
Now that the body is emitted, we compute the next value of the iteration variable by adding the step value, or 1.0 if it isn't present. 'NextVar' will be the value of the loop variable on the next iteration of the loop.
// Compute the end condition. Value *EndCond = End->Codegen(); if (EndCond == 0) return EndCond; // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE(EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond");
Finally, we evaluate the exit value of the loop, to determine whether the loop should exit. This mirrors the condition evaluation for the if/then/else statement.
// Create the "after loop" block and insert it. BasicBlock *LoopEndBB = Builder.GetInsertBlock(); BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. Builder.SetInsertPoint(AfterBB);
With the code for the body of the loop complete, we just need to finish up the control flow for it. This code remembers the end block (for the phi node), then creates the block for the loop exit ("afterloop"). Based on the value of the exit condition, it creates a conditional branch that chooses between executing the loop again and exiting the loop. Any future code is emitted in the "afterloop" block, so it sets the insertion position to it.
// Add a new entry to the PHI node for the backedge. Variable->addIncoming(NextVar, LoopEndBB); // Restore the unshadowed variable. if (OldVal) NamedValues[VarName] = OldVal; else NamedValues.erase(VarName); // for expr always returns 0.0. return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); }
The final code handles various cleanups: now that we have the "NextVar" value, we can add the incoming value to the loop PHI node. After that, we remove the loop variable from the symbol table, so that it isn't in scope after the for loop. Finally, code generation of the for loop always returns 0.0, so that is what we return from ForExprAST::Codegen.
With this, we conclude the "adding control flow to Kaleidoscope" chapter of the tutorial. In this chapter we added two control flow constructs, and used them to motivate a couple of aspects of the LLVM IR that are important for front-end implementors to know. In the next chapter of our saga, we will get a bit crazier and add user-defined operators to our poor innocent language.
Here is the complete code listing for our running example, enhanced with the if/then/else and for expressions.. To build this example, use:
# Compile clang++ -g toy.cpp `llvm-config --cppflags --ldflags --libs core jit native` -O3 -o toy # Run ./toy
Here is the code:
#include "llvm/DerivedTypes.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Support/TargetSelect.h" #include <cstdio> #include <string> #include <map> #include <vector> using namespace llvm; //===----------------------------------------------------------------------===// // Lexer //===----------------------------------------------------------------------===// // The lexer returns tokens [0-255] if it is an unknown character, otherwise one // of these for known things. enum Token { tok_eof = -1, // commands tok_def = -2, tok_extern = -3, // primary tok_identifier = -4, tok_number = -5, // control tok_if = -6, tok_then = -7, tok_else = -8, tok_for = -9, tok_in = -10 }; static std::string IdentifierStr; // Filled in if tok_identifier static double NumVal; // Filled in if tok_number /// gettok - Return the next token from standard input. static int gettok() { static int LastChar = ' '; // Skip any whitespace. while (isspace(LastChar)) LastChar = getchar(); if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* IdentifierStr = LastChar; while (isalnum((LastChar = getchar()))) IdentifierStr += LastChar; if (IdentifierStr == "def") return tok_def; if (IdentifierStr == "extern") return tok_extern; if (IdentifierStr == "if") return tok_if; if (IdentifierStr == "then") return tok_then; if (IdentifierStr == "else") return tok_else; if (IdentifierStr == "for") return tok_for; if (IdentifierStr == "in") return tok_in; return tok_identifier; } if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ std::string NumStr; do { NumStr += LastChar; LastChar = getchar(); } while (isdigit(LastChar) || LastChar == '.'); NumVal = strtod(NumStr.c_str(), 0); return tok_number; } if (LastChar == '#') { // Comment until end of line. do LastChar = getchar(); while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); if (LastChar != EOF) return gettok(); } // Check for end of file. Don't eat the EOF. if (LastChar == EOF) return tok_eof; // Otherwise, just return the character as its ascii value. int ThisChar = LastChar; LastChar = getchar(); return ThisChar; } //===----------------------------------------------------------------------===// // Abstract Syntax Tree (aka Parse Tree) //===----------------------------------------------------------------------===// /// ExprAST - Base class for all expression nodes. class ExprAST { public: virtual ~ExprAST() {} virtual Value *Codegen() = 0; }; /// NumberExprAST - Expression class for numeric literals like "1.0". class NumberExprAST : public ExprAST { double Val; public: NumberExprAST(double val) : Val(val) {} virtual Value *Codegen(); }; /// VariableExprAST - Expression class for referencing a variable, like "a". class VariableExprAST : public ExprAST { std::string Name; public: VariableExprAST(const std::string &name) : Name(name) {} virtual Value *Codegen(); }; /// BinaryExprAST - Expression class for a binary operator. class BinaryExprAST : public ExprAST { char Op; ExprAST *LHS, *RHS; public: BinaryExprAST(char op, ExprAST *lhs, ExprAST *rhs) : Op(op), LHS(lhs), RHS(rhs) {} virtual Value *Codegen(); }; /// CallExprAST - Expression class for function calls. class CallExprAST : public ExprAST { std::string Callee; std::vector<ExprAST*> Args; public: CallExprAST(const std::string &callee, std::vector<ExprAST*> &args) : Callee(callee), Args(args) {} virtual Value *Codegen(); }; /// IfExprAST - Expression class for if/then/else. class IfExprAST : public ExprAST { ExprAST *Cond, *Then, *Else; public: IfExprAST(ExprAST *cond, ExprAST *then, ExprAST *_else) : Cond(cond), Then(then), Else(_else) {} virtual Value *Codegen(); }; /// ForExprAST - Expression class for for/in. class ForExprAST : public ExprAST { std::string VarName; ExprAST *Start, *End, *Step, *Body; public: ForExprAST(const std::string &varname, ExprAST *start, ExprAST *end, ExprAST *step, ExprAST *body) : VarName(varname), Start(start), End(end), Step(step), Body(body) {} virtual Value *Codegen(); }; /// PrototypeAST - This class represents the "prototype" for a function, /// which captures its name, and its argument names (thus implicitly the number /// of arguments the function takes). class PrototypeAST { std::string Name; std::vector<std::string> Args; public: PrototypeAST(const std::string &name, const std::vector<std::string> &args) : Name(name), Args(args) {} Function *Codegen(); }; /// FunctionAST - This class represents a function definition itself. class FunctionAST { PrototypeAST *Proto; ExprAST *Body; public: FunctionAST(PrototypeAST *proto, ExprAST *body) : Proto(proto), Body(body) {} Function *Codegen(); }; //===----------------------------------------------------------------------===// // Parser //===----------------------------------------------------------------------===// /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current /// token the parser is looking at. getNextToken reads another token from the /// lexer and updates CurTok with its results. static int CurTok; static int getNextToken() { return CurTok = gettok(); } /// BinopPrecedence - This holds the precedence for each binary operator that is /// defined. static std::map<char, int> BinopPrecedence; /// GetTokPrecedence - Get the precedence of the pending binary operator token. static int GetTokPrecedence() { if (!isascii(CurTok)) return -1; // Make sure it's a declared binop. int TokPrec = BinopPrecedence[CurTok]; if (TokPrec <= 0) return -1; return TokPrec; } /// Error* - These are little helper functions for error handling. ExprAST *Error(const char *Str) { fprintf(stderr, "Error: %s\n", Str);return 0;} PrototypeAST *ErrorP(const char *Str) { Error(Str); return 0; } FunctionAST *ErrorF(const char *Str) { Error(Str); return 0; } static ExprAST *ParseExpression(); /// identifierexpr /// ::= identifier /// ::= identifier '(' expression* ')' static ExprAST *ParseIdentifierExpr() { std::string IdName = IdentifierStr; getNextToken(); // eat identifier. if (CurTok != '(') // Simple variable ref. return new VariableExprAST(IdName); // Call. getNextToken(); // eat ( std::vector<ExprAST*> Args; if (CurTok != ')') { while (1) { ExprAST *Arg = ParseExpression(); if (!Arg) return 0; Args.push_back(Arg); if (CurTok == ')') break; if (CurTok != ',') return Error("Expected ')' or ',' in argument list"); getNextToken(); } } // Eat the ')'. getNextToken(); return new CallExprAST(IdName, Args); } /// numberexpr ::= number static ExprAST *ParseNumberExpr() { ExprAST *Result = new NumberExprAST(NumVal); getNextToken(); // consume the number return Result; } /// parenexpr ::= '(' expression ')' static ExprAST *ParseParenExpr() { getNextToken(); // eat (. ExprAST *V = ParseExpression(); if (!V) return 0; if (CurTok != ')') return Error("expected ')'"); getNextToken(); // eat ). return V; } /// ifexpr ::= 'if' expression 'then' expression 'else' expression static ExprAST *ParseIfExpr() { getNextToken(); // eat the if. // condition. ExprAST *Cond = ParseExpression(); if (!Cond) return 0; if (CurTok != tok_then) return Error("expected then"); getNextToken(); // eat the then ExprAST *Then = ParseExpression(); if (Then == 0) return 0; if (CurTok != tok_else) return Error("expected else"); getNextToken(); ExprAST *Else = ParseExpression(); if (!Else) return 0; return new IfExprAST(Cond, Then, Else); } /// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression static ExprAST *ParseForExpr() { getNextToken(); // eat the for. if (CurTok != tok_identifier) return Error("expected identifier after for"); std::string IdName = IdentifierStr; getNextToken(); // eat identifier. if (CurTok != '=') return Error("expected '=' after for"); getNextToken(); // eat '='. ExprAST *Start = ParseExpression(); if (Start == 0) return 0; if (CurTok != ',') return Error("expected ',' after for start value"); getNextToken(); ExprAST *End = ParseExpression(); if (End == 0) return 0; // The step value is optional. ExprAST *Step = 0; if (CurTok == ',') { getNextToken(); Step = ParseExpression(); if (Step == 0) return 0; } if (CurTok != tok_in) return Error("expected 'in' after for"); getNextToken(); // eat 'in'. ExprAST *Body = ParseExpression(); if (Body == 0) return 0; return new ForExprAST(IdName, Start, End, Step, Body); } /// primary /// ::= identifierexpr /// ::= numberexpr /// ::= parenexpr /// ::= ifexpr /// ::= forexpr static ExprAST *ParsePrimary() { switch (CurTok) { default: return Error("unknown token when expecting an expression"); case tok_identifier: return ParseIdentifierExpr(); case tok_number: return ParseNumberExpr(); case '(': return ParseParenExpr(); case tok_if: return ParseIfExpr(); case tok_for: return ParseForExpr(); } } /// binoprhs /// ::= ('+' primary)* static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) { // If this is a binop, find its precedence. while (1) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, // consume it, otherwise we are done. if (TokPrec < ExprPrec) return LHS; // Okay, we know this is a binop. int BinOp = CurTok; getNextToken(); // eat binop // Parse the primary expression after the binary operator. ExprAST *RHS = ParsePrimary(); if (!RHS) return 0; // If BinOp binds less tightly with RHS than the operator after RHS, let // the pending operator take RHS as its LHS. int NextPrec = GetTokPrecedence(); if (TokPrec < NextPrec) { RHS = ParseBinOpRHS(TokPrec+1, RHS); if (RHS == 0) return 0; } // Merge LHS/RHS. LHS = new BinaryExprAST(BinOp, LHS, RHS); } } /// expression /// ::= primary binoprhs /// static ExprAST *ParseExpression() { ExprAST *LHS = ParsePrimary(); if (!LHS) return 0; return ParseBinOpRHS(0, LHS); } /// prototype /// ::= id '(' id* ')' static PrototypeAST *ParsePrototype() { if (CurTok != tok_identifier) return ErrorP("Expected function name in prototype"); std::string FnName = IdentifierStr; getNextToken(); if (CurTok != '(') return ErrorP("Expected '(' in prototype"); std::vector<std::string> ArgNames; while (getNextToken() == tok_identifier) ArgNames.push_back(IdentifierStr); if (CurTok != ')') return ErrorP("Expected ')' in prototype"); // success. getNextToken(); // eat ')'. return new PrototypeAST(FnName, ArgNames); } /// definition ::= 'def' prototype expression static FunctionAST *ParseDefinition() { getNextToken(); // eat def. PrototypeAST *Proto = ParsePrototype(); if (Proto == 0) return 0; if (ExprAST *E = ParseExpression()) return new FunctionAST(Proto, E); return 0; } /// toplevelexpr ::= expression static FunctionAST *ParseTopLevelExpr() { if (ExprAST *E = ParseExpression()) { // Make an anonymous proto. PrototypeAST *Proto = new PrototypeAST("", std::vector<std::string>()); return new FunctionAST(Proto, E); } return 0; } /// external ::= 'extern' prototype static PrototypeAST *ParseExtern() { getNextToken(); // eat extern. return ParsePrototype(); } //===----------------------------------------------------------------------===// // Code Generation //===----------------------------------------------------------------------===// static Module *TheModule; static IRBuilder<> Builder(getGlobalContext()); static std::map<std::string, Value*> NamedValues; static FunctionPassManager *TheFPM; Value *ErrorV(const char *Str) { Error(Str); return 0; } Value *NumberExprAST::Codegen() { return ConstantFP::get(getGlobalContext(), APFloat(Val)); } Value *VariableExprAST::Codegen() { // Look this variable up in the function. Value *V = NamedValues[Name]; return V ? V : ErrorV("Unknown variable name"); } Value *BinaryExprAST::Codegen() { Value *L = LHS->Codegen(); Value *R = RHS->Codegen(); if (L == 0 || R == 0) return 0; switch (Op) { case '+': return Builder.CreateFAdd(L, R, "addtmp"); case '-': return Builder.CreateFSub(L, R, "subtmp"); case '*': return Builder.CreateFMul(L, R, "multmp"); case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), "booltmp"); default: return ErrorV("invalid binary operator"); } } Value *CallExprAST::Codegen() { // Look up the name in the global module table. Function *CalleeF = TheModule->getFunction(Callee); if (CalleeF == 0) return ErrorV("Unknown function referenced"); // If argument mismatch error. if (CalleeF->arg_size() != Args.size()) return ErrorV("Incorrect # arguments passed"); std::vector<Value*> ArgsV; for (unsigned i = 0, e = Args.size(); i != e; ++i) { ArgsV.push_back(Args[i]->Codegen()); if (ArgsV.back() == 0) return 0; } return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::Codegen() { Value *CondV = Cond->Codegen(); if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE(CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. Builder.SetInsertPoint(ThenBB); Value *ThenV = Then->Codegen(); if (ThenV == 0) return 0; Builder.CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. ThenBB = Builder.GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); Builder.SetInsertPoint(ElseBB); Value *ElseV = Else->Codegen(); if (ElseV == 0) return 0; Builder.CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. ElseBB = Builder.GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); return PN; } Value *ForExprAST::Codegen() { // Output this as: // ... // start = startexpr // goto loop // loop: // variable = phi [start, loopheader], [nextvariable, loopend] // ... // bodyexpr // ... // loopend: // step = stepexpr // nextvariable = variable + step // endcond = endexpr // br endcond, loop, endloop // outloop: // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->Codegen(); if (StartVal == 0) return 0; // Make the new basic block for the loop header, inserting after current // block. Function *TheFunction = Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = Builder.GetInsertBlock(); BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); // Start insertion in LoopBB. Builder.SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, VarName.c_str()); Variable->addIncoming(StartVal, PreheaderBB); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. Value *OldVal = NamedValues[VarName]; NamedValues[VarName] = Variable; // Emit the body of the loop. This, like any other expr, can change the // current BB. Note that we ignore the value computed by the body, but don't // allow an error. if (Body->Codegen() == 0) return 0; // Emit the step value. Value *StepVal; if (Step) { StepVal = Step->Codegen(); if (StepVal == 0) return 0; } else { // If not specified, use 1.0. StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); } Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); // Compute the end condition. Value *EndCond = End->Codegen(); if (EndCond == 0) return EndCond; // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE(EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *LoopEndBB = Builder.GetInsertBlock(); BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. Builder.SetInsertPoint(AfterBB); // Add a new entry to the PHI node for the backedge. Variable->addIncoming(NextVar, LoopEndBB); // Restore the unshadowed variable. if (OldVal) NamedValues[VarName] = OldVal; else NamedValues.erase(VarName); // for expr always returns 0.0. return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); } Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. std::vector<Type*> Doubles(Args.size(), Type::getDoubleTy(getGlobalContext())); FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule); // If F conflicted, there was already something named 'Name'. If it has a // body, don't allow redefinition or reextern. if (F->getName() != Name) { // Delete the one we just made and get the existing one. F->eraseFromParent(); F = TheModule->getFunction(Name); // If F already has a body, reject this. if (!F->empty()) { ErrorF("redefinition of function"); return 0; } // If F took a different number of args, reject. if (F->arg_size() != Args.size()) { ErrorF("redefinition of function with different # args"); return 0; } } // Set names for all arguments. unsigned Idx = 0; for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); ++AI, ++Idx) { AI->setName(Args[Idx]); // Add arguments to variable symbol table. NamedValues[Args[Idx]] = AI; } return F; } Function *FunctionAST::Codegen() { NamedValues.clear(); Function *TheFunction = Proto->Codegen(); if (TheFunction == 0) return 0; // Create a new basic block to start insertion into. BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); Builder.SetInsertPoint(BB); if (Value *RetVal = Body->Codegen()) { // Finish off the function. Builder.CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); // Optimize the function. TheFPM->run(*TheFunction); return TheFunction; } // Error reading body, remove function. TheFunction->eraseFromParent(); return 0; } //===----------------------------------------------------------------------===// // Top-Level parsing and JIT Driver //===----------------------------------------------------------------------===// static ExecutionEngine *TheExecutionEngine; static void HandleDefinition() { if (FunctionAST *F = ParseDefinition()) { if (Function *LF = F->Codegen()) { fprintf(stderr, "Read function definition:"); LF->dump(); } } else { // Skip token for error recovery. getNextToken(); } } static void HandleExtern() { if (PrototypeAST *P = ParseExtern()) { if (Function *F = P->Codegen()) { fprintf(stderr, "Read extern: "); F->dump(); } } else { // Skip token for error recovery. getNextToken(); } } static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (FunctionAST *F = ParseTopLevelExpr()) { if (Function *LF = F->Codegen()) { // JIT the function, returning a function pointer. void *FPtr = TheExecutionEngine->getPointerToFunction(LF); // Cast it to the right type (takes no arguments, returns a double) so we // can call it as a native function. double (*FP)() = (double (*)())(intptr_t)FPtr; fprintf(stderr, "Evaluated to %f\n", FP()); } } else { // Skip token for error recovery. getNextToken(); } } /// top ::= definition | external | expression | ';' static void MainLoop() { while (1) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: return; case ';': getNextToken(); break; // ignore top-level semicolons. case tok_def: HandleDefinition(); break; case tok_extern: HandleExtern(); break; default: HandleTopLevelExpression(); break; } } } //===----------------------------------------------------------------------===// // "Library" functions that can be "extern'd" from user code. //===----------------------------------------------------------------------===// /// putchard - putchar that takes a double and returns 0. extern "C" double putchard(double X) { putchar((char)X); return 0; } //===----------------------------------------------------------------------===// // Main driver code. //===----------------------------------------------------------------------===// int main() { InitializeNativeTarget(); LLVMContext &Context = getGlobalContext(); // Install standard binary operators. // 1 is lowest precedence. BinopPrecedence['<'] = 10; BinopPrecedence['+'] = 20; BinopPrecedence['-'] = 20; BinopPrecedence['*'] = 40; // highest. // Prime the first token. fprintf(stderr, "ready> "); getNextToken(); // Make the module, which holds all the code. TheModule = new Module("my cool jit", Context); // Create the JIT. This takes ownership of the module. std::string ErrStr; TheExecutionEngine = EngineBuilder(TheModule).setErrorStr(&ErrStr).create(); if (!TheExecutionEngine) { fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str()); exit(1); } FunctionPassManager OurFPM(TheModule); // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); // Provide basic AliasAnalysis support for GVN. OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. OurFPM.add(createReassociatePass()); // Eliminate Common SubExpressions. OurFPM.add(createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). OurFPM.add(createCFGSimplificationPass()); OurFPM.doInitialization(); // Set the global so the code gen can use this. TheFPM = &OurFPM; // Run the main "interpreter loop" now. MainLoop(); TheFPM = 0; // Print out all of the generated code. TheModule->dump(); return 0; }