mirror of
https://github.com/CatalaLang/catala.git
synced 2024-11-09 22:16:10 +03:00
refactor(tests): udpates tests based on the english lexer
This commit is contained in:
parent
304f6a27ae
commit
a42d0c7728
@ -1,14 +1,14 @@
|
||||
@@Include: ../tutorial_en.catala_en@@
|
||||
> Include: ../tutorial_en.catala_en
|
||||
|
||||
@Test@
|
||||
## [Test]
|
||||
|
||||
/*
|
||||
```catala
|
||||
declaration scope UnitTest1:
|
||||
context tax_computation scope NewIncomeTaxComputation
|
||||
|
||||
scope UnitTest1:
|
||||
definition
|
||||
tax_computation.individual
|
||||
tax_computation.individual
|
||||
equals
|
||||
Individual {
|
||||
-- income: $230,000
|
||||
@ -26,4 +26,4 @@ scope UnitTest2:
|
||||
}
|
||||
|
||||
assertion tax_computation.income_tax = $0.00
|
||||
*/
|
||||
```
|
||||
|
@ -1,206 +1,222 @@
|
||||
@@The Catala language tutorial@@
|
||||
## The Catala language tutorial
|
||||
|
||||
Welcome to this tutorial, whose objective is to guide you through the features
|
||||
of the Catala language and teach you how to annotate a legislative text using
|
||||
the language. This document is addressed primarily to developers or people that
|
||||
have a programming background, though tech-savvy lawyers will probably figure
|
||||
Welcome to this tutorial, whose objective is to guide you through the features
|
||||
of the Catala language and teach you how to annotate a legislative text using
|
||||
the language. This document is addressed primarily to developers or people that
|
||||
have a programming background, though tech-savvy lawyers will probably figure
|
||||
things out.
|
||||
|
||||
@@Literate programming@@+
|
||||
### Literate programming
|
||||
|
||||
To begin writing a Catala program, you must start from the text of the
|
||||
legislative source that will justify the code that you will write. Concretely,
|
||||
that means copy-pasting the text of the law into a Catala source file and
|
||||
formatting it according so that Catala can understand it. Catala source files
|
||||
have the ".catala_en" extension. If you were to write a Catala program for a
|
||||
To begin writing a Catala program, you must start from the text of the
|
||||
legislative source that will justify the code that you will write. Concretely,
|
||||
that means copy-pasting the text of the law into a Catala source file and
|
||||
formatting it according so that Catala can understand it. Catala source files
|
||||
have the ".catala_en" extension. If you were to write a Catala program for a
|
||||
French law, you would use the ".catala_fr" extension.
|
||||
|
||||
You can write any kind of plain text in Catala, and it will be printed as is
|
||||
in PDF or HTML output. You can split your text into short lines, those
|
||||
will appear as a single paragraph in the output. If you want to create a
|
||||
new paragrah, you have to leave a blank line in the source.
|
||||
You can write any kind of plain text in Catala, and it will be printed as is
|
||||
in PDF or HTML output. You can split your text into short lines, those
|
||||
will appear as a single paragraph in the output. If you want to create a
|
||||
new paragrah, you have to leave a blank line in the source.
|
||||
|
||||
Catala allows you to declare section or subsection headers as it is done
|
||||
here, with the "at" symbol repeated twice. You can define heading of lower
|
||||
importance by adding increasing numbers of "+" after the title of the heading.
|
||||
here, with the "at" symbol repeated twice. You can define heading of lower
|
||||
importance by adding increasing numbers of "+" after the title of the heading.
|
||||
|
||||
The fundamental division unit is the article, introduced by a single "at".
|
||||
Let's analyse a fictional example that defines an income tax.
|
||||
|
||||
@Article 1@
|
||||
The income tax for an individual is defined as a fixed percentage of the
|
||||
#### [Article 1]
|
||||
|
||||
The income tax for an individual is defined as a fixed percentage of the
|
||||
individual's income over a year.
|
||||
|
||||
/*
|
||||
# Welcome to the code mode of Catala. This is a comment, because the line is
|
||||
```catala
|
||||
# Welcome to the code mode of Catala. This is a comment, because the line is
|
||||
# prefixed by #.
|
||||
# We will soon learn what to write here in order to translate the meaning
|
||||
# We will soon learn what to write here in order to translate the meaning
|
||||
# of the article into Catala code.
|
||||
*/
|
||||
```
|
||||
|
||||
To do that, we will intertwine short snippets of code between the sentences of
|
||||
the legislative text. Each snippet of code should be as short as possible and
|
||||
as close as possible to the actual sentence that justifies the code. This style
|
||||
is called literate programming, a programming paradigm invented by the famous
|
||||
To do that, we will intertwine short snippets of code between the sentences of
|
||||
the legislative text. Each snippet of code should be as short as possible and
|
||||
as close as possible to the actual sentence that justifies the code. This style
|
||||
is called literate programming, a programming paradigm invented by the famous
|
||||
computer scientist Donald Knuth in the 70s.
|
||||
|
||||
@@Defining a fictional income tax@@+
|
||||
### Defining a fictional income tax
|
||||
|
||||
The content of article 1 uses a lot of implicit context: there exists an
|
||||
individual with an income, as well as an income tax that the individual has
|
||||
to pay each year. Even if this implicit context is not verbatim in the law,
|
||||
we have to explicit it for programming purposes. Concretely, we need a
|
||||
"metadata" section that defines the shape and types of the data used
|
||||
The content of article 1 uses a lot of implicit context: there exists an
|
||||
individual with an income, as well as an income tax that the individual has
|
||||
to pay each year. Even if this implicit context is not verbatim in the law,
|
||||
we have to explicit it for programming purposes. Concretely, we need a
|
||||
"metadata" section that defines the shape and types of the data used
|
||||
inside the law.
|
||||
|
||||
Let's start our metadata section by declaring the type information for the
|
||||
Let's start our metadata section by declaring the type information for the
|
||||
individual:
|
||||
|
||||
@@Begin metadata@@
|
||||
/*
|
||||
> Begin metadata
|
||||
|
||||
```catala
|
||||
declaration structure Individual:
|
||||
# The name of the structure "Individual", must start with an
|
||||
# uppercase letter: this is the CamelCase convention.
|
||||
data income content money
|
||||
# In this line, "income" is the name of the structure field and
|
||||
# In this line, "income" is the name of the structure field and
|
||||
# "money" is the type of what is stored in that field.
|
||||
# Available types include: integer, decimal, money, date, duration,
|
||||
# Available types include: integer, decimal, money, date, duration,
|
||||
# and any other structure or enumeration that you declare
|
||||
data number_of_children content integer
|
||||
# "income" and "number_of_children" start by a lowercase letter,
|
||||
# "income" and "number_of_children" start by a lowercase letter,
|
||||
# they follow the snake_case convention
|
||||
*/
|
||||
@@End metadata@@
|
||||
```
|
||||
|
||||
This structure contains two data fields, "income" and "number_of_children". Structures are
|
||||
useful to group together data that goes together. Usually, you
|
||||
get one structure per concrete object on which the law applies (like the
|
||||
individual). It is up to you to decide how to group the data together,
|
||||
> End metadata
|
||||
|
||||
This structure contains two data fields, "income" and "number_of_children". Structures are
|
||||
useful to group together data that goes together. Usually, you
|
||||
get one structure per concrete object on which the law applies (like the
|
||||
individual). It is up to you to decide how to group the data together,
|
||||
but you should aim to optimize code readability.
|
||||
|
||||
Sometimes, the law gives an enumeration of different situations. These
|
||||
Sometimes, the law gives an enumeration of different situations. These
|
||||
enumerations are modeled in Catala using an enumeration type, like:
|
||||
@@Begin metadata@@
|
||||
/*
|
||||
|
||||
> Begin metadata
|
||||
|
||||
```catala
|
||||
declaration enumeration TaxCredit:
|
||||
# The name "TaxCredit" is also written in CamelCase
|
||||
# The name "TaxCredit" is also written in CamelCase
|
||||
-- NoTaxCredit
|
||||
# This line says that "TaxCredit" can be a "NoTaxCredit" situation
|
||||
-- ChildrenTaxCredit content integer
|
||||
# This line says that alternatively, "TaxCredit" can be a
|
||||
-- ChildrenTaxCredit content integer
|
||||
# This line says that alternatively, "TaxCredit" can be a
|
||||
# "ChildrenTaxCredit" situation. This situation carries a content
|
||||
# of type integer corresponding to the number of children concerned
|
||||
# of type integer corresponding to the number of children concerned
|
||||
# by the tax credit. This means that if you're in the "ChildrenTaxCredit"
|
||||
# situation, you will also have access to this number of children
|
||||
*/
|
||||
@@End metadata@@
|
||||
# situation, you will also have access to this number of children
|
||||
```
|
||||
|
||||
In computer science terms, such an enumeration is called a "sum type" or simply
|
||||
an enum. The combination of structures and enumerations allow the Catala
|
||||
programmer to declare all possible shapes of data, as they are equivalent to
|
||||
the powerful notion of "algebraic datatypes".
|
||||
> End metadata
|
||||
|
||||
We've defined and typed the data that the program will manipulate. Now we have
|
||||
to define the logical context in which these data will evolve. This is done in
|
||||
Catala using "scopes". Scopes are close to functions in terms of traditional
|
||||
In computer science terms, such an enumeration is called a "sum type" or simply
|
||||
an enum. The combination of structures and enumerations allow the Catala
|
||||
programmer to declare all possible shapes of data, as they are equivalent to
|
||||
the powerful notion of "algebraic datatypes".
|
||||
|
||||
We've defined and typed the data that the program will manipulate. Now we have
|
||||
to define the logical context in which these data will evolve. This is done in
|
||||
Catala using "scopes". Scopes are close to functions in terms of traditional
|
||||
programming. Scopes also have to be declared in metadata, so here we go:
|
||||
|
||||
@@Begin metadata@@
|
||||
/*
|
||||
> Begin metadata
|
||||
|
||||
```catala
|
||||
declaration scope IncomeTaxComputation:
|
||||
# Scope names use CamelCase
|
||||
context individual content Individual
|
||||
# This line declares a context element of the scope, which is akin to
|
||||
# a function parameter in computer science term. This is the piece of
|
||||
# This line declares a context element of the scope, which is akin to
|
||||
# a function parameter in computer science term. This is the piece of
|
||||
# data on which the scope will operate
|
||||
context fixed_percentage content decimal
|
||||
context income_tax content money
|
||||
*/
|
||||
@@End metadata@@
|
||||
```
|
||||
|
||||
We now have everything to annotate the contents of article 1, which is copied
|
||||
> End metadata
|
||||
|
||||
We now have everything to annotate the contents of article 1, which is copied
|
||||
over below.
|
||||
|
||||
@Article 1@
|
||||
The income tax for an individual is defined as a fixed percentage of the
|
||||
#### [Article 1]
|
||||
|
||||
The income tax for an individual is defined as a fixed percentage of the
|
||||
individual's income over a year.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope IncomeTaxComputation:
|
||||
definition income_tax equals
|
||||
individual.income *$ fixed_percentage
|
||||
*/
|
||||
```
|
||||
|
||||
In the code, we are defining inside our scope the amount of the income tax
|
||||
according to the formula described in the article. When defining formulae,
|
||||
you have access to all the usual arithmetic operators: addition "+",
|
||||
substraction "-", multiplication "*" and division (slash).
|
||||
In the code, we are defining inside our scope the amount of the income tax
|
||||
according to the formula described in the article. When defining formulae,
|
||||
you have access to all the usual arithmetic operators: addition "+",
|
||||
substraction "-", multiplication "*" and division (slash).
|
||||
|
||||
However, in the Catala code, you can see that we use "*$" to multiply the
|
||||
individual income by the fixed percentage. The $ suffix indicates that we
|
||||
are performing a multiplication on an amount of money. Indeed, in Catala,
|
||||
you have to keep track of what you are dealing with: is it money ? Is it
|
||||
an integer? Using just "+" or "*" can be ambiguous in terms of rounding,
|
||||
since money is usually rounded at the cent. So to disambiguate, we suffix these
|
||||
operations with something that indicates the type of what we manipulate.
|
||||
The suffixes are "$" for money "." for decimals, "at" (like in email adresses)
|
||||
for dates and the hat symbol for durations. If you forget the suffix, the Catala type
|
||||
checker will display an error message that will help you put it where it
|
||||
belongs.
|
||||
However, in the Catala code, you can see that we use "*$" to multiply the
|
||||
individual income by the fixed percentage. The $ suffix indicates that we
|
||||
are performing a multiplication on an amount of money. Indeed, in Catala,
|
||||
you have to keep track of what you are dealing with: is it money ? Is it
|
||||
an integer? Using just "+" or "*" can be ambiguous in terms of rounding,
|
||||
since money is usually rounded at the cent. So to disambiguate, we suffix these
|
||||
operations with something that indicates the type of what we manipulate.
|
||||
The suffixes are "$" for money "." for decimals, "at" (like in email adresses)
|
||||
for dates and the hat symbol for durations. If you forget the suffix, the Catala type
|
||||
checker will display an error message that will help you put it where it
|
||||
belongs.
|
||||
|
||||
But inside article 1, one question remains unknown: what is the value of
|
||||
But inside article 1, one question remains unknown: what is the value of
|
||||
of the fixed percentage? Often, precise values are defined elsewhere in the
|
||||
legislative source. Here, let's suppose we have:
|
||||
|
||||
@Article 2@
|
||||
#### [Article 2]
|
||||
|
||||
The fixed percentage mentionned at article 1 is equal to 20 %.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope IncomeTaxComputation:
|
||||
definition fixed_percentage equals 20 %
|
||||
# Writing 20% is just an abbreviation for 0.20
|
||||
*/
|
||||
```
|
||||
|
||||
You can see here that Catala allows definitions to be scattered throughout
|
||||
You can see here that Catala allows definitions to be scattered throughout
|
||||
the annotation of the legislative text, so that each
|
||||
definition is as close as possible to its location in the text.
|
||||
|
||||
@@Conditional definitions@@+
|
||||
### Conditional definitions
|
||||
|
||||
So far so good, but now the legislative text introduces some trickiness. Let us
|
||||
So far so good, but now the legislative text introduces some trickiness. Let us
|
||||
suppose the third article says:
|
||||
|
||||
@Article 3@ If the individual is in charge of 2 or more children, then the fixed
|
||||
#### [Article 3]
|
||||
|
||||
If the individual is in charge of 2 or more children, then the fixed
|
||||
percentage mentionned at article 1 is equal to 15 %.
|
||||
/*
|
||||
|
||||
```catala
|
||||
# How to redefine fixed_percentage?
|
||||
*/
|
||||
```
|
||||
|
||||
This article actually gives another definition for the fixed percentage, which
|
||||
was already defined in article 2. However, article 3 defines the percentage
|
||||
conditionnally to the individual having more than 2 children. Catala allows
|
||||
was already defined in article 2. However, article 3 defines the percentage
|
||||
conditionnally to the individual having more than 2 children. Catala allows
|
||||
you precisely to redefine a variable under a condition:
|
||||
|
||||
/*
|
||||
```catala
|
||||
scope IncomeTaxComputation:
|
||||
definition fixed_percentage under condition
|
||||
individual.number_of_children >= 2
|
||||
consequence equals 15 %
|
||||
# Writing 15% is just an abbreviation for 0.15
|
||||
*/
|
||||
```
|
||||
|
||||
When the Catala program will execute, the right definition will be dynamically
|
||||
chosen by looking at which condition is true. A correctly drafted legislative
|
||||
source should always ensure that at most one condition is true at all times.
|
||||
However, if it is not the case, Catala will let you define a precedence on the
|
||||
chosen by looking at which condition is true. A correctly drafted legislative
|
||||
source should always ensure that at most one condition is true at all times.
|
||||
However, if it is not the case, Catala will let you define a precedence on the
|
||||
conditions, which has to be justified by the law.
|
||||
|
||||
### Functions
|
||||
|
||||
@@Functions@@+
|
||||
|
||||
Catala lets you define functions anywhere in your data. Here's what it looks
|
||||
like in the metadata definition when we want to define a two-brackets tax
|
||||
Catala lets you define functions anywhere in your data. Here's what it looks
|
||||
like in the metadata definition when we want to define a two-brackets tax
|
||||
computation:
|
||||
@@Begin metadata@@
|
||||
/*
|
||||
|
||||
> Begin metadata
|
||||
|
||||
```catala
|
||||
declaration structure TwoBrackets:
|
||||
data breakpoint content money
|
||||
data rate1 content decimal
|
||||
@ -209,38 +225,44 @@ declaration structure TwoBrackets:
|
||||
declaration scope TwoBracketsTaxComputation :
|
||||
context brackets content TwoBrackets
|
||||
context tax_formula content money depends on money
|
||||
*/
|
||||
@@End metadata@@
|
||||
```
|
||||
|
||||
> End metadata
|
||||
|
||||
And in the code:
|
||||
|
||||
@Article4@ The tax amount for a two-brackets computation is equal to the amount
|
||||
#### [Article4]
|
||||
|
||||
The tax amount for a two-brackets computation is equal to the amount
|
||||
of income in each bracket multiplied by the rate of each bracket.
|
||||
|
||||
/*
|
||||
```catala
|
||||
scope TwoBracketsTaxComputation :
|
||||
definition tax_formula of income equals
|
||||
if income <=$ brackets.breakpoint then
|
||||
income *$ brackets.rate1
|
||||
else (
|
||||
brackets.breakpoint *$ brackets.rate1 +$
|
||||
brackets.breakpoint *$ brackets.rate1 +$
|
||||
(income -$ brackets.breakpoint) *$ brackets.rate2
|
||||
)
|
||||
*/
|
||||
```
|
||||
|
||||
@@Scope inclusion@@+
|
||||
### Scope inclusion
|
||||
|
||||
Now that we've defined our helper scope for computing a two-brackets tax, we
|
||||
Now that we've defined our helper scope for computing a two-brackets tax, we
|
||||
want to use it in our main tax computation scope.
|
||||
|
||||
@Article 5@ For individuals whose income is greater than $100,000, the income
|
||||
tax of article 1 is 40% of the income above $100,000. Below $100,000, the
|
||||
#### [Article 5]
|
||||
|
||||
For individuals whose income is greater than $100,000, the income
|
||||
tax of article 1 is 40% of the income above $100,000. Below $100,000, the
|
||||
income tax is 20% of the income.
|
||||
/*
|
||||
|
||||
```catala
|
||||
declaration scope NewIncomeTaxComputation:
|
||||
context two_brackets scope TwoBracketsTaxComputation
|
||||
# This line says that we add the item two_brackets to the context.
|
||||
# However, the "scope" keyword tells that this item is not a piece of data
|
||||
# However, the "scope" keyword tells that this item is not a piece of data
|
||||
# but rather a subscope that we can use to compute things.
|
||||
context individual content Individual
|
||||
context income_tax content money
|
||||
@ -251,62 +273,66 @@ scope NewIncomeTaxComputation :
|
||||
-- rate1: 20%
|
||||
-- rate2: 40%
|
||||
}
|
||||
definition income_tax equals two_brackets.tax_formula of individual.income
|
||||
*/
|
||||
definition income_tax equals two_brackets.tax_formula of individual.income
|
||||
```
|
||||
|
||||
@Article 6@
|
||||
Individuals earning less than $10,000 are exempted of the income tax mentionned
|
||||
#### [Article 6]
|
||||
|
||||
Individuals earning less than $10,000 are exempted of the income tax mentionned
|
||||
at article 1.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope NewIncomeTaxComputation:
|
||||
definition income_tax under condition
|
||||
definition income_tax under condition
|
||||
individual.income <=$ $10,000
|
||||
consequence equals $0
|
||||
*/
|
||||
```
|
||||
|
||||
That's it! We've defined a two-brackets tax computation simply by annotating
|
||||
legislative article by snippets of Catala code. However, attentive readers
|
||||
may have caught something weird in articles 5 and 6. What happens when the
|
||||
income of the individual is between $10,000 and $100,000 ?
|
||||
That's it! We've defined a two-brackets tax computation simply by annotating
|
||||
legislative article by snippets of Catala code. However, attentive readers
|
||||
may have caught something weird in articles 5 and 6. What happens when the
|
||||
income of the individual is between $10,000 and $100,000 ?
|
||||
|
||||
The law leaves it unspecified ; our dummy articles are clearly badly drafted.
|
||||
But Catala can help you find this sort of errors via simple testing or
|
||||
The law leaves it unspecified ; our dummy articles are clearly badly drafted.
|
||||
But Catala can help you find this sort of errors via simple testing or
|
||||
even formal verification. Let's start with the testing.
|
||||
|
||||
@@Testing Catala programs@@+
|
||||
### Testing Catala programs
|
||||
|
||||
Testing Catala programs can be done directly into Catala. Indeed, writing test
|
||||
cases for each Catala scope that you define is a good practice called
|
||||
"unit testing" in the software engineering community. A test case is defined
|
||||
cases for each Catala scope that you define is a good practice called
|
||||
"unit testing" in the software engineering community. A test case is defined
|
||||
as another scope:
|
||||
|
||||
@Testing NewIncomeTaxComputation@
|
||||
/*
|
||||
#### [Testing NewIncomeTaxComputation]
|
||||
|
||||
```catala
|
||||
declaration scope Test1:
|
||||
context tax_computation scope NewIncomeTaxComputation
|
||||
context income_tax content money
|
||||
|
||||
scope Test1:
|
||||
definition
|
||||
tax_computation.individual
|
||||
tax_computation.individual
|
||||
# We define the argument to the subscope
|
||||
equals
|
||||
# The four lines below define a whole structure by giving a value to
|
||||
# The four lines below define a whole structure by giving a value to
|
||||
# each of its fields
|
||||
Individual {
|
||||
-- income: $230,000
|
||||
-- number_of_children: 0
|
||||
}
|
||||
|
||||
|
||||
definition income_tax equals tax_computation.income_tax
|
||||
# Next, we retrieve the income tax value compute it by the subscope and
|
||||
# Next, we retrieve the income tax value compute it by the subscope and
|
||||
# assert that it is equal to the expected value :
|
||||
# ($230,000-$100,00)*40%+$100,000*20% = $72,000
|
||||
assertion income_tax = $72,000
|
||||
*/
|
||||
```
|
||||
|
||||
This test should pass. Let us now consider a failing test case:
|
||||
/*
|
||||
|
||||
```catala
|
||||
declaration scope Test2:
|
||||
context tax_computation scope NewIncomeTaxComputation
|
||||
context income_tax content money
|
||||
@ -319,24 +345,24 @@ scope Test2:
|
||||
|
||||
definition income_tax equals tax_computation.income_tax
|
||||
assertion income_tax = $0
|
||||
*/
|
||||
```
|
||||
|
||||
This test case should compute a $0 income tax because of Article 6. But instead,
|
||||
execution will yield an error saying that there is a conflict between rules.
|
||||
execution will yield an error saying that there is a conflict between rules.
|
||||
|
||||
@@Defining exceptions to rules@@+
|
||||
### Defining exceptions to rules
|
||||
|
||||
Indeed, the definition of the income tax in article 6 conflicts with the
|
||||
definition of income tax in article 5. But actually, article 6 is just an
|
||||
exception of article 5. In the law, it is implicit that if article 6 is
|
||||
Indeed, the definition of the income tax in article 6 conflicts with the
|
||||
definition of income tax in article 5. But actually, article 6 is just an
|
||||
exception of article 5. In the law, it is implicit that if article 6 is
|
||||
applicable, then it takes precedence over article 5.
|
||||
|
||||
@Fixing the computation@
|
||||
#### [Fixing the computation]
|
||||
|
||||
This implicit precedence has to be explicitely declared in Catala. Here is a
|
||||
fixed version of the NewIncomeTaxComputation scope:
|
||||
|
||||
/*
|
||||
```catala
|
||||
declaration scope NewIncomeTaxComputationFixed:
|
||||
context two_brackets scope TwoBracketsTaxComputation
|
||||
context individual content Individual
|
||||
@ -349,22 +375,22 @@ scope NewIncomeTaxComputationFixed :
|
||||
-- rate2: 40%
|
||||
}
|
||||
|
||||
# To define an exception to a rule, you have to first label the rule that
|
||||
# To define an exception to a rule, you have to first label the rule that
|
||||
# you want to attach the exception to. You can put any snake_case identifier
|
||||
# for the label
|
||||
label article_5
|
||||
definition income_tax equals two_brackets.tax_formula of individual.income
|
||||
label article_5
|
||||
definition income_tax equals two_brackets.tax_formula of individual.income
|
||||
|
||||
# Then, you can declare the exception by referring back to the label
|
||||
exception article_5
|
||||
definition income_tax under condition
|
||||
definition income_tax under condition
|
||||
individual.income <=$ $10,000
|
||||
consequence equals $0
|
||||
*/
|
||||
```
|
||||
|
||||
And the test that should now work:
|
||||
|
||||
/*
|
||||
```catala
|
||||
declaration scope Test3:
|
||||
context tax_computation scope NewIncomeTaxComputationFixed
|
||||
context income_tax content money
|
||||
@ -374,17 +400,17 @@ scope Test3:
|
||||
-- income: $4,000
|
||||
-- number_of_children: 0
|
||||
}
|
||||
definition income_tax equals tax_computation.income_tax
|
||||
definition income_tax equals tax_computation.income_tax
|
||||
assertion income_tax = $0
|
||||
*/
|
||||
```
|
||||
|
||||
@@Conclusion@@+
|
||||
### Conclusion
|
||||
|
||||
This tutorial presents the basic concepts and syntax of the Catala language
|
||||
features. It is then up to you use them to annotate legislative texts
|
||||
This tutorial presents the basic concepts and syntax of the Catala language
|
||||
features. It is then up to you use them to annotate legislative texts
|
||||
with their algorithmic translation.
|
||||
|
||||
There is no single way to write Catala programs, as the program style should be
|
||||
adapted to the legislation it annotates. However, Catala is a functional
|
||||
language at heart, so following standard functional programming design patterns
|
||||
There is no single way to write Catala programs, as the program style should be
|
||||
adapted to the legislation it annotates. However, Catala is a functional
|
||||
language at heart, so following standard functional programming design patterns
|
||||
should help achieve concise and readable code.
|
||||
|
@ -1,14 +1,15 @@
|
||||
@@Section 121@@
|
||||
## Section 121
|
||||
|
||||
@@Begin metadata@@
|
||||
/*
|
||||
> Begin metadata
|
||||
|
||||
```catala
|
||||
declaration structure Period:
|
||||
data begin content date
|
||||
data begin content date
|
||||
data end content date
|
||||
|
||||
declaration scope PeriodMerge:
|
||||
context periods1 content collection Period
|
||||
context periods2 content collection Period
|
||||
context periods1 content collection Period
|
||||
context periods2 content collection Period
|
||||
context output content collection Period
|
||||
|
||||
scope PeriodMerge:
|
||||
@ -17,7 +18,7 @@ scope PeriodMerge:
|
||||
definition periods2 equals []
|
||||
|
||||
# TODO: find a way to implement the merging of two collections of date
|
||||
# periods into a single non-overlapping collection of date periods such
|
||||
# periods into a single non-overlapping collection of date periods such
|
||||
# that the output covers both input date ranges.
|
||||
definition output equals []
|
||||
|
||||
@ -26,43 +27,43 @@ declaration structure PreviousSaleWhereSection121aApplied:
|
||||
|
||||
|
||||
declaration enumeration OtherSection121aSale:
|
||||
-- NoOtherSaleWhereSection121aApplied
|
||||
-- MostRecentSaleWhereSection121aApplied content
|
||||
-- NoOtherSaleWhereSection121aApplied
|
||||
-- MostRecentSaleWhereSection121aApplied content
|
||||
PreviousSaleWhereSection121aApplied
|
||||
|
||||
declaration scope Section121SinglePerson:
|
||||
context requirements_met condition
|
||||
context requirements_ownership_met condition
|
||||
context requirements_met condition
|
||||
context requirements_ownership_met condition
|
||||
context requirements_usage_met condition
|
||||
context date_of_sale_or_exchange content date
|
||||
context property_ownage content collection Period
|
||||
# Invariant: the periods in the collection are disjoint
|
||||
context property_usage_as_principal_residence
|
||||
context property_usage_as_principal_residence
|
||||
content collection Period
|
||||
# Invariant: the periods in the collection are disjoint
|
||||
context aggregate_periods_from_last_five_years content duration
|
||||
context aggregate_periods_from_last_five_years content duration
|
||||
depends on collection Period
|
||||
context gain_cap content money
|
||||
context gain_from_sale_or_exchange_of_property content money
|
||||
context income_excluded_from_gross_income_uncapped content money
|
||||
context income_excluded_from_gross_income content money
|
||||
context section_121_b_3_applies condition
|
||||
context section_121_b_3_applies condition
|
||||
context other_section_121a_sale content OtherSection121aSale
|
||||
|
||||
declaration structure PersonalData:
|
||||
data property_ownage content collection Period
|
||||
data property_usage_as_principal_residence
|
||||
data property_usage_as_principal_residence
|
||||
content collection Period
|
||||
data other_section_121a_sale content OtherSection121aSale
|
||||
|
||||
declaration structure JointReturn:
|
||||
data person1 content PersonalData
|
||||
data person2 content PersonalData
|
||||
declaration structure JointReturn:
|
||||
data person1 content PersonalData
|
||||
data person2 content PersonalData
|
||||
|
||||
declaration structure DeadSpouseInfo:
|
||||
data return content PersonalData
|
||||
data date_of_spouse_death content date
|
||||
data death_spouse_info_at_time_of_death content PersonalData
|
||||
data death_spouse_info_at_time_of_death content PersonalData
|
||||
|
||||
declaration enumeration ReturnType:
|
||||
-- SingleReturn content PersonalData
|
||||
@ -76,10 +77,10 @@ declaration scope Section121TwoPersons:
|
||||
context section121Person2 scope Section121SinglePerson
|
||||
context section121a_requirements_met condition
|
||||
context section_121_b_2_A_condition condition
|
||||
context gain_cap_person_1 content money
|
||||
context gain_cap_person_1 content money
|
||||
context gain_cap_person_2 content money
|
||||
context gain_cap content money
|
||||
context return_type content ReturnType
|
||||
context return_type content ReturnType
|
||||
context return_date content date
|
||||
context date_of_sale_or_exchange content date
|
||||
context gain_from_sale_or_exchange_of_property content money
|
||||
@ -89,49 +90,49 @@ declaration scope Section121TwoPersons:
|
||||
|
||||
# Defining sub-scopes arguments
|
||||
scope Section121TwoPersons:
|
||||
definition section121Person2.date_of_sale_or_exchange equals
|
||||
definition section121Person2.date_of_sale_or_exchange equals
|
||||
date_of_sale_or_exchange
|
||||
definition section121Person1.date_of_sale_or_exchange equals
|
||||
definition section121Person1.date_of_sale_or_exchange equals
|
||||
date_of_sale_or_exchange
|
||||
|
||||
definition person1 equals match return_type with pattern
|
||||
definition person1 equals match return_type with pattern
|
||||
-- SingleReturn of data_person1 : data_person1
|
||||
-- JointReturn of data_couple : data_couple.person1
|
||||
-- SingleReturnSurvivingSpouse of data_single: data_single.return
|
||||
|
||||
definition person2 equals match return_type with pattern
|
||||
definition person2 equals match return_type with pattern
|
||||
-- SingleReturn of data_person2 : data_person2
|
||||
-- JointReturn of data_couple : data_couple.person2
|
||||
-- SingleReturnSurvivingSpouse of data_single: data_single.return
|
||||
|
||||
definition section121Person1.property_ownage equals person1.property_ownage
|
||||
|
||||
definition section121Person1.property_usage_as_principal_residence equals
|
||||
definition section121Person1.property_usage_as_principal_residence equals
|
||||
person1.property_usage_as_principal_residence
|
||||
|
||||
definition section121Person2.property_ownage equals person2.property_ownage
|
||||
|
||||
definition section121Person2.property_usage_as_principal_residence equals
|
||||
definition section121Person2.property_usage_as_principal_residence equals
|
||||
person1.property_usage_as_principal_residence
|
||||
|
||||
definition section121Person1.gain_from_sale_or_exchange_of_property equals
|
||||
definition section121Person1.gain_from_sale_or_exchange_of_property equals
|
||||
gain_from_sale_or_exchange_of_property
|
||||
definition section121Person2.gain_from_sale_or_exchange_of_property equals
|
||||
definition section121Person2.gain_from_sale_or_exchange_of_property equals
|
||||
gain_from_sale_or_exchange_of_property
|
||||
|
||||
definition section121Person1.other_section_121a_sale equals
|
||||
definition section121Person1.other_section_121a_sale equals
|
||||
person1.other_section_121a_sale
|
||||
|
||||
definition section121Person2.other_section_121a_sale equals
|
||||
person2.other_section_121a_sale
|
||||
|
||||
definition gain_cap_person_1 equals section121Person1.gain_cap
|
||||
definition gain_cap_person_1 equals section121Person1.gain_cap
|
||||
definition gain_cap_person_2 equals section121Person2.gain_cap
|
||||
|
||||
declaration scope Section121TwoPasses:
|
||||
context first_pass scope Section121TwoPersons
|
||||
context second_pass scope Section121TwoPersons
|
||||
context return_type content ReturnType
|
||||
context return_type content ReturnType
|
||||
context return_date content date
|
||||
context date_of_sale_or_exchange content date
|
||||
context gain_from_sale_or_exchange_of_property content money
|
||||
@ -140,308 +141,316 @@ declaration scope Section121TwoPasses:
|
||||
|
||||
# Defining sub-scopes arguments
|
||||
scope Section121TwoPasses:
|
||||
definition first_pass.return_type equals return_type
|
||||
definition second_pass.return_type equals return_type
|
||||
|
||||
definition first_pass.return_date equals return_date
|
||||
definition second_pass.return_date equals return_date
|
||||
definition first_pass.return_type equals return_type
|
||||
definition second_pass.return_type equals return_type
|
||||
|
||||
definition first_pass.gain_from_sale_or_exchange_of_property equals
|
||||
definition first_pass.return_date equals return_date
|
||||
definition second_pass.return_date equals return_date
|
||||
|
||||
definition first_pass.gain_from_sale_or_exchange_of_property equals
|
||||
gain_from_sale_or_exchange_of_property
|
||||
definition second_pass.gain_from_sale_or_exchange_of_property equals
|
||||
definition second_pass.gain_from_sale_or_exchange_of_property equals
|
||||
gain_from_sale_or_exchange_of_property
|
||||
|
||||
definition first_pass.date_of_sale_or_exchange equals date_of_sale_or_exchange
|
||||
definition second_pass.date_of_sale_or_exchange equals date_of_sale_or_exchange
|
||||
|
||||
definition income_excluded_from_gross_income equals
|
||||
definition income_excluded_from_gross_income equals
|
||||
second_pass.income_excluded_from_gross_income
|
||||
*/
|
||||
@@End metadata@@
|
||||
```
|
||||
> End metadata
|
||||
|
||||
@(a) Exclusion@
|
||||
## [(a) Exclusion]
|
||||
|
||||
Gross income shall not include gain from the sale or exchange of property if,
|
||||
during the 5-year period ending on the date of the sale or exchange, such
|
||||
property has been owned and used by the taxpayer as the taxpayer’s principal
|
||||
residence for periods aggregating 2 years or more.
|
||||
/*
|
||||
Gross income shall not include gain from the sale or exchange of property if,
|
||||
during the 5-year period ending on the date of the sale or exchange, such
|
||||
property has been owned and used by the taxpayer as the taxpayer’s principal
|
||||
residence for periods aggregating 2 years or more.
|
||||
|
||||
```catala
|
||||
scope Section121SinglePerson:
|
||||
# Here we aggregate over all the periods of the collection. For
|
||||
# Here we aggregate over all the periods of the collection. For
|
||||
# each period, three cases:
|
||||
# - either the period began less that 5 years before the
|
||||
# - either the period began less that 5 years before the
|
||||
# date_of_sale_or_exchange in which case we count if full
|
||||
# - either the period ended more that 5 years before the
|
||||
# date_of_sale_or_exchange in which case we don't count it
|
||||
# - either the 5 years mark is inside the period and we only
|
||||
# - either the period ended more that 5 years before the
|
||||
# date_of_sale_or_exchange in which case we don't count it
|
||||
# - either the 5 years mark is inside the period and we only
|
||||
# cound the half after 5 years
|
||||
definition aggregate_periods_from_last_five_years of periods equals
|
||||
definition aggregate_periods_from_last_five_years of periods equals
|
||||
sum duration for period in periods of (
|
||||
if date_of_sale_or_exchange <=@ period.begin +@ 5 year then
|
||||
period.end -@ period.begin
|
||||
else (if date_of_sale_or_exchange >=@ period.end +@ 5 year then
|
||||
0 day
|
||||
else (if date_of_sale_or_exchange >=@ period.end +@ 5 year then
|
||||
0 day
|
||||
else ((period.end +@ 5 year) -@ date_of_sale_or_exchange))
|
||||
)
|
||||
|
||||
# Regulation 1.121-1(c)(1): 2 years = 730 days
|
||||
# Regulation 1.121-1(c)(1): the periods of ownage and usage
|
||||
# Regulation 1.121-1(c)(1): the periods of ownage and usage
|
||||
# don't have to overlap
|
||||
rule requirements_ownership_met under condition
|
||||
rule requirements_ownership_met under condition
|
||||
aggregate_periods_from_last_five_years of property_ownage >=^ 730 day
|
||||
consequence fulfilled
|
||||
consequence fulfilled
|
||||
|
||||
rule requirements_usage_met under condition
|
||||
rule requirements_usage_met under condition
|
||||
aggregate_periods_from_last_five_years of
|
||||
property_usage_as_principal_residence >=^ 730 day
|
||||
consequence fulfilled
|
||||
|
||||
rule requirements_met under condition
|
||||
rule requirements_met under condition
|
||||
requirements_ownership_met and requirements_usage_met
|
||||
consequence fulfilled
|
||||
|
||||
definition income_excluded_from_gross_income_uncapped equals
|
||||
if requirements_met then gain_from_sale_or_exchange_of_property
|
||||
else $0
|
||||
|
||||
|
||||
scope Section121TwoPersons:
|
||||
definition section121a_requirements_met equals section121Person1.requirements_met
|
||||
|
||||
definition income_excluded_from_gross_income_uncapped equals
|
||||
definition income_excluded_from_gross_income_uncapped equals
|
||||
section121Person1.income_excluded_from_gross_income_uncapped
|
||||
|
||||
*/
|
||||
```
|
||||
|
||||
@@(b) Limitations@@+
|
||||
### (b) Limitations
|
||||
|
||||
@(1) In general@
|
||||
#### [(1) In general]
|
||||
|
||||
The amount of gain excluded from gross income under subsection (a) with
|
||||
The amount of gain excluded from gross income under subsection (a) with
|
||||
respect to any sale or exchange shall not exceed $250,000.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope Section121SinglePerson:
|
||||
definition gain_cap equals $250,000
|
||||
|
||||
# Big semantics insight for Catala. Here we could want to get rid of
|
||||
# the "_uncapped" version of the variable. But in the current
|
||||
|
||||
# Big semantics insight for Catala. Here we could want to get rid of
|
||||
# the "_uncapped" version of the variable. But in the current
|
||||
# semantics we can't do that because we don't allow for recursion.
|
||||
definition income_excluded_from_gross_income equals
|
||||
if income_excluded_from_gross_income_uncapped >=$ gain_cap then
|
||||
definition income_excluded_from_gross_income equals
|
||||
if income_excluded_from_gross_income_uncapped >=$ gain_cap then
|
||||
gain_cap
|
||||
else
|
||||
else
|
||||
income_excluded_from_gross_income_uncapped
|
||||
|
||||
scope Section121TwoPersons:
|
||||
definition gain_cap equals section121Person1.gain_cap
|
||||
scope Section121TwoPersons:
|
||||
definition gain_cap equals section121Person1.gain_cap
|
||||
|
||||
definition income_excluded_from_gross_income equals
|
||||
if income_excluded_from_gross_income_uncapped >=$ gain_cap then
|
||||
definition income_excluded_from_gross_income equals
|
||||
if income_excluded_from_gross_income_uncapped >=$ gain_cap then
|
||||
gain_cap
|
||||
else
|
||||
else
|
||||
income_excluded_from_gross_income_uncapped
|
||||
*/
|
||||
```
|
||||
|
||||
@(2) Special rules for joint returns@
|
||||
#### [(2) Special rules for joint returns]
|
||||
|
||||
In the case of a husband and wife who make a joint return for the taxable year
|
||||
In the case of a husband and wife who make a joint return for the taxable year
|
||||
of the sale or exchange of the property—
|
||||
|
||||
/*
|
||||
```catala
|
||||
# Taxable year of the sale or exchange ?=? year when the income is taxed
|
||||
# Imagine a couple selling the house in 2020 and getting the payment in
|
||||
# 2021 where they file a joint return. Does (A) apply or not ?
|
||||
# Imagine a couple selling the house in 2020 and getting the payment in
|
||||
# 2021 where they file a joint return. Does (A) apply or not ?
|
||||
# Reasonably it should.
|
||||
*/
|
||||
```
|
||||
|
||||
@(A) $500,000 Limitation for certain joint returns@
|
||||
#### [(A) $500,000 Limitation for certain joint returns]
|
||||
|
||||
Paragraph (1) shall be applied by substituting “$500,000” for “$250,000” if—
|
||||
|
||||
(i) either spouse meets the ownership requirements of subsection (a) with
|
||||
respect to such property;
|
||||
|
||||
(ii) both spouses meet the use requirements of subsection (a) with respect to
|
||||
(ii) both spouses meet the use requirements of subsection (a) with respect to
|
||||
such property; and
|
||||
|
||||
(iii) neither spouse is ineligible for the benefits of subsection (a) with
|
||||
(iii) neither spouse is ineligible for the benefits of subsection (a) with
|
||||
respect to such property by reason of paragraph (3).
|
||||
|
||||
/*
|
||||
```catala
|
||||
scope Section121TwoPersons:
|
||||
rule section_121_b_2_A_condition under condition
|
||||
rule section_121_b_2_A_condition under condition
|
||||
(return_type with pattern JointReturn of data_couple)
|
||||
and
|
||||
# i)
|
||||
(section121Person1.requirements_ownership_met or
|
||||
section121Person2.requirements_ownership_met)
|
||||
and
|
||||
# ii)
|
||||
(section121Person1.requirements_usage_met and
|
||||
# i)
|
||||
(section121Person1.requirements_ownership_met or
|
||||
section121Person2.requirements_ownership_met)
|
||||
and
|
||||
# ii)
|
||||
(section121Person1.requirements_usage_met and
|
||||
section121Person2.requirements_usage_met)
|
||||
# iii)
|
||||
and
|
||||
(not (section121Person1.section_121_b_3_applies))
|
||||
and
|
||||
(not (section121Person2.section_121_b_3_applies))
|
||||
and
|
||||
(not (section121Person2.section_121_b_3_applies))
|
||||
consequence fulfilled
|
||||
|
||||
|
||||
exception
|
||||
rule section121a_requirements_met under condition
|
||||
section_121_b_2_A_condition
|
||||
rule section121a_requirements_met under condition
|
||||
section_121_b_2_A_condition
|
||||
consequence fulfilled
|
||||
|
||||
exception
|
||||
definition gain_cap under condition
|
||||
|
||||
exception
|
||||
definition gain_cap under condition
|
||||
section_121_b_2_A_condition
|
||||
consequence equals $500,000
|
||||
*/
|
||||
```
|
||||
|
||||
@(B) Other joint returns@
|
||||
If such spouses do not meet the requirements of subparagraph (A), the limitation
|
||||
under paragraph (1) shall be the sum of the limitations under paragraph (1) to
|
||||
which each spouse would be entitled if such spouses had not been married. For
|
||||
purposes of the preceding sentence, each spouse shall be treated as owning the
|
||||
#### [(B) Other joint returns]
|
||||
|
||||
If such spouses do not meet the requirements of subparagraph (A), the limitation
|
||||
under paragraph (1) shall be the sum of the limitations under paragraph (1) to
|
||||
which each spouse would be entitled if such spouses had not been married. For
|
||||
purposes of the preceding sentence, each spouse shall be treated as owning the
|
||||
property during the period that either spouse owned the property.
|
||||
/*
|
||||
scope Section121TwoPasses under condition
|
||||
(return_type with pattern JointReturn) and
|
||||
|
||||
```catala
|
||||
scope Section121TwoPasses under condition
|
||||
(return_type with pattern JointReturn) and
|
||||
not (first_pass.section_121_b_2_A_condition):
|
||||
|
||||
definition second_pass.gain_cap equals
|
||||
first_pass.gain_cap_person_1 +$
|
||||
definition second_pass.gain_cap equals
|
||||
first_pass.gain_cap_person_1 +$
|
||||
first_pass.gain_cap_person_2
|
||||
|
||||
definition period_merge.periods1 equals match return_type with pattern
|
||||
definition period_merge.periods1 equals match return_type with pattern
|
||||
-- JointReturn of joint_return: joint_return.person1.property_ownage
|
||||
-- SingleReturnSurvivingSpouse of dead_spouse_info : [] # does not happen
|
||||
-- SingleReturn of return : [] # does not happen
|
||||
definition period_merge.periods2 equals match return_type with pattern
|
||||
definition period_merge.periods2 equals match return_type with pattern
|
||||
-- JointReturn of joint_return: joint_return.person2.property_ownage
|
||||
-- SingleReturnSurvivingSpouse of dead_spouse_info : [] # does not happen
|
||||
-- SingleReturn of return : [] # does not happen
|
||||
|
||||
definition second_pass.person1 equals PersonalData {
|
||||
-- property_ownage: period_merge.output
|
||||
-- property_usage_as_principal_residence:
|
||||
-- property_usage_as_principal_residence:
|
||||
first_pass.person1.property_usage_as_principal_residence
|
||||
-- other_section_121a_sale: first_pass.person1.other_section_121a_sale
|
||||
}
|
||||
definition second_pass.person2 equals PersonalData {
|
||||
-- property_ownage: period_merge.output
|
||||
-- property_usage_as_principal_residence:
|
||||
-- property_usage_as_principal_residence:
|
||||
first_pass.person2.property_usage_as_principal_residence
|
||||
-- other_section_121a_sale: first_pass.person2.other_section_121a_sale
|
||||
}
|
||||
*/
|
||||
@(3) Application to only 1 sale or exchange every 2 years@
|
||||
```
|
||||
|
||||
#### [(3) Application to only 1 sale or exchange every 2 years]
|
||||
|
||||
|
||||
Subsection (a) shall not apply to any sale or exchange by the taxpayer if,
|
||||
during the 2-year period ending on the date of such sale or exchange, there
|
||||
Subsection (a) shall not apply to any sale or exchange by the taxpayer if,
|
||||
during the 2-year period ending on the date of such sale or exchange, there
|
||||
was any other sale or exchange by the taxpayer to which subsection (a) applied.
|
||||
/*
|
||||
scope Section121SinglePerson:
|
||||
rule section_121_b_3_applies under condition
|
||||
(other_section_121a_sale with pattern
|
||||
|
||||
```catala
|
||||
scope Section121SinglePerson:
|
||||
rule section_121_b_3_applies under condition
|
||||
(other_section_121a_sale with pattern
|
||||
MostRecentSaleWhereSection121aApplied of other_sale) and
|
||||
date_of_sale_or_exchange -@ other_sale.date_of_sale_or_exchange <=^ 2 year
|
||||
consequence fulfilled
|
||||
|
||||
exception
|
||||
definition income_excluded_from_gross_income_uncapped under condition
|
||||
exception
|
||||
definition income_excluded_from_gross_income_uncapped under condition
|
||||
section_121_b_3_applies
|
||||
consequence equals $0
|
||||
*/
|
||||
consequence equals $0
|
||||
```
|
||||
|
||||
@(4) Special rule for certain sales by surviving spouses@
|
||||
#### [(4) Special rule for certain sales by surviving spouses]
|
||||
|
||||
/*
|
||||
# Sarah: the year when your spouse dies, do you file a joint return or
|
||||
```catala
|
||||
# Sarah: the year when your spouse dies, do you file a joint return or
|
||||
# separate returns?
|
||||
*/
|
||||
In the case of a sale or exchange of property by an unmarried individual whose
|
||||
spouse is deceased on the date of such sale, paragraph (1) shall be applied by
|
||||
substituting “$500,000” for “$250,000” if such sale occurs not later than 2
|
||||
years after the date of death of such spouse and the requirements of paragraph
|
||||
```
|
||||
In the case of a sale or exchange of property by an unmarried individual whose
|
||||
spouse is deceased on the date of such sale, paragraph (1) shall be applied by
|
||||
substituting “$500,000” for “$250,000” if such sale occurs not later than 2
|
||||
years after the date of death of such spouse and the requirements of paragraph
|
||||
(2)(A) were met immediately before such date of death.
|
||||
/*
|
||||
scope Section121TwoPasses under condition
|
||||
return_type with pattern SingleReturnSurvivingSpouse of single_data and
|
||||
|
||||
```catala
|
||||
scope Section121TwoPasses under condition
|
||||
return_type with pattern SingleReturnSurvivingSpouse of single_data and
|
||||
single_data.date_of_spouse_death <@ date_of_sale_or_exchange and
|
||||
date_of_sale_or_exchange <=@ single_data.date_of_spouse_death +@ 2 year
|
||||
date_of_sale_or_exchange <=@ single_data.date_of_spouse_death +@ 2 year
|
||||
:
|
||||
|
||||
definition first_pass.date_of_sale_or_exchange equals
|
||||
|
||||
definition first_pass.date_of_sale_or_exchange equals
|
||||
match return_type with pattern
|
||||
-- SingleReturnSurvivingSpouse of single_data: single_data.date_of_spouse_death
|
||||
-- SingleReturn of return: date_of_sale_or_exchange # does not happen
|
||||
-- JointReturn of return: date_of_sale_or_exchange # does not happen
|
||||
|
||||
definition first_pass.return_type equals
|
||||
match return_type with pattern
|
||||
-- SingleReturnSurvivingSpouse of single_data:
|
||||
match return_type with pattern
|
||||
-- SingleReturnSurvivingSpouse of single_data:
|
||||
JointReturn content (JointReturn {
|
||||
-- person1: single_data.return
|
||||
-- person2: single_data.death_spouse_info_at_time_of_death
|
||||
})
|
||||
-- SingleReturn of return: SingleReturn content return # does not happen
|
||||
-- JointReturn of return: JointReturn content return # does not happen
|
||||
|
||||
definition second_pass.gain_cap under condition
|
||||
|
||||
definition second_pass.gain_cap under condition
|
||||
first_pass.section_121_b_2_A_condition
|
||||
consequence equals $500,000
|
||||
*/
|
||||
```
|
||||
|
||||
@@(5) Exclusion of gain allocated to nonqualified use@@++
|
||||
#### (5) Exclusion of gain allocated to nonqualified use
|
||||
|
||||
@(A) In general@
|
||||
##### [(A) In general]
|
||||
|
||||
Subsection (a) shall not apply to so much of the gain from the sale or exchange
|
||||
Subsection (a) shall not apply to so much of the gain from the sale or exchange
|
||||
of property as is allocated to periods of nonqualified use.
|
||||
|
||||
@(B) Gain allocated to periods of nonqualified use@
|
||||
##### [(B) Gain allocated to periods of nonqualified use]
|
||||
|
||||
For purposes of subparagraph (A), gain shall be allocated to periods of
|
||||
For purposes of subparagraph (A), gain shall be allocated to periods of
|
||||
nonqualified use based on the ratio which—
|
||||
|
||||
(i) the aggregate periods of nonqualified use during the period such property
|
||||
(i) the aggregate periods of nonqualified use during the period such property
|
||||
was owned by the taxpayer, bears to
|
||||
|
||||
(ii) the period such property was owned by the taxpayer.
|
||||
|
||||
@@(C) Period of nonqualified use@@+++
|
||||
##### (C) Period of nonqualified use
|
||||
|
||||
For purposes of this paragraph—
|
||||
|
||||
@(i) In general@
|
||||
###### [(i) In general]
|
||||
|
||||
The term “period of nonqualified use” means any period (other than the portion
|
||||
of any period preceding January 1, 2009) during which the property is not used
|
||||
as the principal residence of the taxpayer or the taxpayer’s spouse or former
|
||||
The term “period of nonqualified use” means any period (other than the portion
|
||||
of any period preceding January 1, 2009) during which the property is not used
|
||||
as the principal residence of the taxpayer or the taxpayer’s spouse or former
|
||||
spouse.
|
||||
|
||||
@(ii) Exceptions@
|
||||
###### [(ii) Exceptions]
|
||||
|
||||
The term “period of nonqualified use” does not include—
|
||||
|
||||
(I) any portion of the 5-year period described in subsection (a) which is after
|
||||
the last date that such property is used as the principal residence of the
|
||||
(I) any portion of the 5-year period described in subsection (a) which is after
|
||||
the last date that such property is used as the principal residence of the
|
||||
taxpayer or the taxpayer’s spouse,
|
||||
|
||||
(II) any period (not to exceed an aggregate period of 10 years) during which the
|
||||
taxpayer or the taxpayer’s spouse is serving on qualified official extended duty
|
||||
(as defined in subsection (d)(9)(C)) described in clause (i), (ii), or (iii) of
|
||||
(II) any period (not to exceed an aggregate period of 10 years) during which the
|
||||
taxpayer or the taxpayer’s spouse is serving on qualified official extended duty
|
||||
(as defined in subsection (d)(9)(C)) described in clause (i), (ii), or (iii) of
|
||||
subsection (d)(9)(A), and
|
||||
|
||||
(III) any other period of temporary absence (not to exceed an aggregate period
|
||||
of 2 years) due to change of employment, health conditions, or such other
|
||||
(III) any other period of temporary absence (not to exceed an aggregate period
|
||||
of 2 years) due to change of employment, health conditions, or such other
|
||||
unforeseen circumstances as may be specified by the Secretary.
|
||||
@(D) Coordination with recognition of gain attributable to depreciation@
|
||||
|
||||
###### [(D) Coordination with recognition of gain attributable to depreciation]
|
||||
|
||||
For purposes of this paragraph—
|
||||
|
||||
(i) subparagraph (A) shall be applied after the application of subsection
|
||||
(i) subparagraph (A) shall be applied after the application of subsection
|
||||
(d)(6), and
|
||||
|
||||
(ii) subparagraph (B) shall be applied without regard to any gain to which
|
||||
(ii) subparagraph (B) shall be applied without regard to any gain to which
|
||||
subsection (d)(6) applies.
|
||||
|
@ -1,7 +1,7 @@
|
||||
@@Section 132@@
|
||||
## Section 132
|
||||
|
||||
@@Begin metadata@@
|
||||
/*
|
||||
> Begin metadata
|
||||
```catala
|
||||
# We only formalize part (c) here
|
||||
declaration enumeration DiscountType:
|
||||
-- Property
|
||||
@ -19,25 +19,27 @@ declaration scope QualifiedEmployeeDiscount:
|
||||
context is_services content boolean
|
||||
|
||||
scope QualifiedEmployeeDiscount:
|
||||
definition is_property equals match discount_type with pattern
|
||||
-- Property: true
|
||||
definition is_property equals match discount_type with pattern
|
||||
-- Property: true
|
||||
-- Services: false
|
||||
definition is_services equals match discount_type with pattern
|
||||
-- Property: false
|
||||
-- Property: false
|
||||
-- Services: true
|
||||
*/
|
||||
@@End metadata@@
|
||||
```
|
||||
> End metadata
|
||||
|
||||
|
||||
@@(c) Qualified employee discount defined@@+
|
||||
### (c) Qualified employee discount defined
|
||||
For purposes of this section—
|
||||
|
||||
@(1) Qualified employee discount@
|
||||
The term “qualified employee discount” means any employee discount with respect
|
||||
#### [(1) Qualified employee discount]
|
||||
|
||||
The term “qualified employee discount” means any employee discount with respect
|
||||
to qualified property or services to the extent such discount does not exceed—
|
||||
(A) in the case of property, the gross profit percentage of the price at which
|
||||
(A) in the case of property, the gross profit percentage of the price at which
|
||||
the property is being offered by the employer to customers, or
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope QualifiedEmployeeDiscount :
|
||||
definition qualified_employee_discount
|
||||
under condition is_property consequence
|
||||
@ -46,10 +48,12 @@ scope QualifiedEmployeeDiscount :
|
||||
customer_price *$ gross_profit_percentage
|
||||
then customer_price *$ gross_profit_percentage
|
||||
else employee_discount
|
||||
*/
|
||||
(B) in the case of services, 20 percent of the price at which the services are
|
||||
```
|
||||
|
||||
(B) in the case of services, 20 percent of the price at which the services are
|
||||
being offered by the employer to customers.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope QualifiedEmployeeDiscount :
|
||||
definition qualified_employee_discount
|
||||
under condition is_services consequence
|
||||
@ -64,57 +68,69 @@ scope QualifiedEmployeeDiscount under condition is_services:
|
||||
# We provide a default value here so that the computations run smooth.
|
||||
definition aggregate_cost equals $0
|
||||
definition gross_profit_percentage equals 0%
|
||||
*/
|
||||
@@(2) Gross profit percentage@@++
|
||||
```
|
||||
|
||||
#### (2) Gross profit percentage
|
||||
|
||||
##### [(A) In general]
|
||||
|
||||
@(A) In general@
|
||||
The term “gross profit percentage” means the percent which—
|
||||
|
||||
(i) the excess of the aggregate sales price of property sold by the employer
|
||||
(i) the excess of the aggregate sales price of property sold by the employer
|
||||
to customers over the aggregate cost of such property to the employer, is of
|
||||
|
||||
(ii) the aggregate sale price of such property.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope QualifiedEmployeeDiscount under condition is_property:
|
||||
assertion customer_price >=$ aggregate_cost
|
||||
|
||||
definition gross_profit_percentage equals
|
||||
(customer_price -$ aggregate_cost) /$ customer_price
|
||||
*/
|
||||
@(B) Determination of gross profit percentage@
|
||||
```
|
||||
|
||||
##### [(B) Determination of gross profit percentage]
|
||||
|
||||
Gross profit percentage shall be determined on the basis of—
|
||||
|
||||
(i) all property offered to customers in the ordinary course of the line of
|
||||
business of the employer in which the employee is performing services (or a
|
||||
(i) all property offered to customers in the ordinary course of the line of
|
||||
business of the employer in which the employee is performing services (or a
|
||||
reasonable classification of property selected by the employer), and
|
||||
|
||||
(ii) the employer’s experience during a representative period.
|
||||
/*
|
||||
|
||||
```catala
|
||||
# (i) and (ii) are subjective criteria for determining the gross profit
|
||||
# percentage ; we do not formalize them
|
||||
*/
|
||||
@(3) Employee discount defined@
|
||||
```
|
||||
|
||||
##### [(3) Employee discount defined]
|
||||
|
||||
The term “employee discount” means the amount by which—
|
||||
|
||||
(A) the price at which the property or services are provided by the employer to
|
||||
(A) the price at which the property or services are provided by the employer to
|
||||
an employee for use by such employee, is less than
|
||||
|
||||
(B) the price at which such property or services are being offered by the
|
||||
(B) the price at which such property or services are being offered by the
|
||||
employer to customers.
|
||||
/*
|
||||
|
||||
```catala
|
||||
scope QualifiedEmployeeDiscount:
|
||||
assertion customer_price >=$ employee_price
|
||||
|
||||
definition employee_discount equals
|
||||
customer_price -$ employee_price
|
||||
*/
|
||||
@(4) Qualified property or services@
|
||||
The term “qualified property or services” means any property (other than real
|
||||
property and other than personal property of a kind held for investment) or
|
||||
services which are offered for sale to customers in the ordinary course of
|
||||
the line of business of the employer in which the employee is performing
|
||||
```
|
||||
|
||||
##### [(4) Qualified property or services]
|
||||
|
||||
The term “qualified property or services” means any property (other than real
|
||||
property and other than personal property of a kind held for investment) or
|
||||
services which are offered for sale to customers in the ordinary course of
|
||||
the line of business of the employer in which the employee is performing
|
||||
services.
|
||||
/*
|
||||
|
||||
```catala
|
||||
# Again, this is for subjectively determining what item qualifies for a
|
||||
# discount, not formalizing
|
||||
*/
|
||||
```
|
||||
|
@ -1,17 +1,17 @@
|
||||
@@Include: ../section_121.catala_en@@
|
||||
> Include: ../section_121.catala_en
|
||||
|
||||
@Testing paragraph (a)@
|
||||
## [Testing paragraph (a)]
|
||||
|
||||
/*
|
||||
```catala
|
||||
declaration scope Data:
|
||||
context period_four_years_recent content Period
|
||||
context period_one_year_recent content Period
|
||||
context period_four_years_recent content Period
|
||||
context period_one_year_recent content Period
|
||||
context period_two_years_middle content Period
|
||||
context date_of_sale_or_exchange content date
|
||||
context gain_from_sale_or_exchange_of_property content money
|
||||
context return_date content date
|
||||
context person_ok_1 content PersonalData
|
||||
context person_ok_2 content PersonalData
|
||||
context person_ok_1 content PersonalData
|
||||
context person_ok_2 content PersonalData
|
||||
context person_ko_1 content PersonalData
|
||||
context person_ko_2 content PersonalData
|
||||
|
||||
@ -38,7 +38,7 @@ scope Data:
|
||||
}
|
||||
definition person_ok_2 equals PersonalData {
|
||||
-- property_ownage: [period_four_years_recent]
|
||||
-- property_usage_as_principal_residence:
|
||||
-- property_usage_as_principal_residence:
|
||||
[period_two_years_middle; period_one_year_recent]
|
||||
-- other_section_121a_sale: NoOtherSaleWhereSection121aApplied
|
||||
}
|
||||
@ -53,9 +53,9 @@ scope Data:
|
||||
-- property_usage_as_principal_residence: [period_two_years_middle]
|
||||
-- other_section_121a_sale: NoOtherSaleWhereSection121aApplied
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
####################### Testing Section121SinglePerson #########################
|
||||
|
||||
@ -65,7 +65,7 @@ declaration scope Test1:
|
||||
|
||||
scope Test1:
|
||||
definition scope121a.date_of_sale_or_exchange equals data_.date_of_sale_or_exchange
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
data_.gain_from_sale_or_exchange_of_property
|
||||
definition scope121a.property_ownage equals [data_.period_four_years_recent]
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
@ -79,10 +79,10 @@ declaration scope Test2:
|
||||
|
||||
scope Test2:
|
||||
definition scope121a.date_of_sale_or_exchange equals data_.date_of_sale_or_exchange
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
data_.gain_from_sale_or_exchange_of_property
|
||||
definition scope121a.property_ownage equals [data_.period_four_years_recent]
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
[data_.period_one_year_recent]
|
||||
definition scope121a.other_section_121a_sale equals NoOtherSaleWhereSection121aApplied
|
||||
assertion not scope121a.requirements_met
|
||||
@ -93,10 +93,10 @@ declaration scope Test3:
|
||||
|
||||
scope Test3:
|
||||
definition scope121a.date_of_sale_or_exchange equals data_.date_of_sale_or_exchange
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
data_.gain_from_sale_or_exchange_of_property
|
||||
definition scope121a.property_ownage equals [data_.period_four_years_recent]
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
[data_.period_two_years_middle]
|
||||
definition scope121a.other_section_121a_sale equals NoOtherSaleWhereSection121aApplied
|
||||
assertion not scope121a.requirements_met
|
||||
@ -107,10 +107,10 @@ declaration scope Test4:
|
||||
|
||||
scope Test4:
|
||||
definition scope121a.date_of_sale_or_exchange equals data_.date_of_sale_or_exchange
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
definition scope121a.gain_from_sale_or_exchange_of_property equals
|
||||
data_.gain_from_sale_or_exchange_of_property
|
||||
definition scope121a.property_ownage equals [data_.period_four_years_recent]
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
definition scope121a.property_usage_as_principal_residence equals
|
||||
[data_.period_two_years_middle; data_.period_one_year_recent]
|
||||
definition scope121a.other_section_121a_sale equals NoOtherSaleWhereSection121aApplied
|
||||
assertion scope121a.requirements_met
|
||||
@ -121,10 +121,10 @@ declaration scope Test5:
|
||||
context scope121 scope Section121TwoPersons
|
||||
context data_ scope Data
|
||||
|
||||
scope Test5:
|
||||
scope Test5:
|
||||
definition scope121.date_of_sale_or_exchange equals data_.date_of_sale_or_exchange
|
||||
definition scope121.return_date equals data_.return_date
|
||||
definition scope121.gain_from_sale_or_exchange_of_property equals
|
||||
definition scope121.gain_from_sale_or_exchange_of_property equals
|
||||
data_.gain_from_sale_or_exchange_of_property
|
||||
definition scope121.return_type equals SingleReturn content data_.person_ok_1
|
||||
assertion scope121.income_excluded_from_gross_income = $250,000
|
||||
@ -133,14 +133,14 @@ declaration scope Test6:
|
||||
context scope121 scope Section121TwoPersons
|
||||
context data_ scope Data
|
||||
|
||||
scope Test6:
|
||||
scope Test6:
|
||||
definition scope121.date_of_sale_or_exchange equals data_.date_of_sale_or_exchange
|
||||
definition scope121.return_date equals data_.return_date
|
||||
definition scope121.gain_from_sale_or_exchange_of_property equals
|
||||
definition scope121.gain_from_sale_or_exchange_of_property equals
|
||||
data_.gain_from_sale_or_exchange_of_property
|
||||
definition scope121.return_type equals JointReturn content (JointReturn {
|
||||
-- person1: data_.person_ok_1
|
||||
-- person2: data_.person_ok_2
|
||||
})
|
||||
assertion scope121.income_excluded_from_gross_income = $350,000
|
||||
*/
|
||||
```
|
||||
|
@ -1,9 +1,10 @@
|
||||
@@Include: ../section_132.catala_en@@
|
||||
> Include: ../section_132.catala_en
|
||||
|
||||
@Test@
|
||||
/*
|
||||
### [Test]
|
||||
|
||||
```catala
|
||||
declaration scope TestSection132_1:
|
||||
context section_132 scope QualifiedEmployeeDiscount
|
||||
context section_132 scope QualifiedEmployeeDiscount
|
||||
|
||||
scope TestSection132_1:
|
||||
definition section_132.customer_price equals $1500
|
||||
@ -13,11 +14,11 @@ scope TestSection132_1:
|
||||
assertion section_132.employee_discount = $500
|
||||
assertion section_132.gross_profit_percentage = 0.4
|
||||
assertion section_132.qualified_employee_discount = $500
|
||||
*/
|
||||
```
|
||||
|
||||
/*
|
||||
```catala
|
||||
declaration scope TestSection132_2:
|
||||
context section_132 scope QualifiedEmployeeDiscount
|
||||
context section_132 scope QualifiedEmployeeDiscount
|
||||
|
||||
scope TestSection132_2:
|
||||
definition section_132.customer_price equals $1500
|
||||
@ -27,11 +28,11 @@ scope TestSection132_2:
|
||||
assertion section_132.employee_discount = $500
|
||||
assertion section_132.gross_profit_percentage = 0.2
|
||||
assertion section_132.qualified_employee_discount = $300.00
|
||||
*/
|
||||
```
|
||||
|
||||
/*
|
||||
```catala
|
||||
declaration scope TestSection132_3:
|
||||
context section_132 scope QualifiedEmployeeDiscount
|
||||
context section_132 scope QualifiedEmployeeDiscount
|
||||
|
||||
scope TestSection132_3:
|
||||
definition section_132.customer_price equals $1500
|
||||
@ -39,4 +40,4 @@ scope TestSection132_3:
|
||||
definition section_132.discount_type equals Services
|
||||
assertion section_132.employee_discount = $500
|
||||
assertion section_132.qualified_employee_discount = $300
|
||||
*/
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user